0

What I want is something like an onchange event with an html select element. But apparently the change event is for the options in a select. I need to detect when a new option is added.

I've searched google and SO and the links within but I don't want to use any frameworks.

I read up on creating events but I don't understand how to use the created event "onAdded". Like select.onAdded -> how does select know something (an option) is added?

Or is there a simpler way that I'm over looking? An event that I missed?

My point is, I want to do something like this

var select = document.getElementById("slct");

var btn =  document.getElementById("btn");
btn.addEventListener("click", () => {
 var option = document.createElement("option");
 option.text = `${select.length} please work!`;
 select.add(option );
  //!!!select optionAdded event should have triggered!!!
})

function addPoint(){
  //do things
}

/*
select.addEventListener("optionAdded", addPoint);
or
onSelectValueCountChanged(appropriateFunctionHere);
*/
<form>
  <select id="slct" style="width: 300px" mutiple="true" size="11">  
  </select>
  
  <button type="button" id="btn">click
  </button>
  
</form>

Is it possible? In an easy to understand (I'm new to js) way without any frameworks?

Community
  • 1
  • 1
  • How are the options being added currently? – Ju66ernaut Nov 21 '16 at 23:00
  • button click. Gets a value from a text input. Then an option is created with the text.value and appended into the select. – Tinkle Pooplebottham Nov 21 '16 at 23:03
  • If you are adding the options yourself don't you already have the event? After you create and append your option, why not just call the function your listener would have done? – Ju66ernaut Nov 21 '16 at 23:05
  • 1
    I guess he perhaps would like a clean, event-based code which can be reused elsewhere too. – Zoltán Tamási Nov 21 '16 at 23:06
  • I thought it would be better to seperate those concerns. What @ZoltánTamási said. – Tinkle Pooplebottham Nov 21 '16 at 23:07
  • Why don't you use `option.selected=true;` and than a simple call to a function like `optionAdded(option);` passing the new option as argument if needed ? You don't need a separate event since you already use one. – Roko C. Buljan Nov 21 '16 at 23:07
  • @ZoltánTamási I considered those options but thought that if I could detect a new value in the select, it would automatically insert the points into my other object, rather then adding an option, the calling another method. eventually the button.click method will get too large. Also, I want to learn more about events including creating them. In the meantime, I will look into your triggerCustomEvent. I'm trying to wrap my head around it. – Tinkle Pooplebottham Nov 21 '16 at 23:17

3 Answers3

1

You can create a custom event and fire it on the select element. Here is a code I used for it some time ago. It should be supported quite well, but cannot tell you precise information on that now.

function triggerCustomEvent(element, eventType, eventProperties) {
  let event;

  // a cross-browser way to create an event object
  // don't know which branch is for which
  if (document.createEvent) {
    event = document.createEvent('HTMLEvents');
    event.initEvent(eventType, true, true);
  } else {
    event = document.createEventObject();
    event.eventType = eventType;
  }

  // also for being cross-browser
  event.eventName = eventType;

  // events are just objects, we can add properties to them, so we extend it
  // with our custom properties if any
  if (eventProperties && typeof eventProperties === "object") {
    for (var property in eventProperties) {
      event[property] = eventProperties[property];
    }
  } 

  // cross-browser way of firing the actual event object on the given element
  if (document.createEvent) {
    element.dispatchEvent(event);
  } else {
    element.fireEvent('on' + event.eventType, event);
  }
}

You can use it like this

triggerCustomEvent(select, "onoptionadded", { options: opt });

The third argument is optional, if you want to add some properties to the fired event object.

If you want to go this way, you should introduce a method for adding options, so you can be sure that you always trigger this event.

function addOption(select, option) {
  select.add(option);
  triggerCustomEvent(select, "onoptionadded", { options: option });
}

Note that the code snippet is only for example purposes, it's not widely tested and you shouldn't just copy-paste it.

Zoltán Tamási
  • 11,389
  • 7
  • 58
  • 81
  • I think this is what I'm looking for. However it seems the consensus is that I should implement the addPoint function after adding an option. It does the same task. I will want to add some other code to though when adding/removing options. But this is good to know how to create events. I saw something similar but this is clearer. – Tinkle Pooplebottham Nov 21 '16 at 23:26
  • You don't have to take all consensus as a must, you can choose whatever tool suites your task best. We have events, so why couldn't we use them :) – Zoltán Tamási Nov 21 '16 at 23:31
1

You will need to create your own custom event for this. Here are the basics:

// Get a reference to the select
var lst = document.getElementById("lstStuff");

// Create the new event
var event = new Event('optionAdded');

// Listen for the event.
lst.addEventListener('optionAdded', function (e) {
   console.log("The " + e.type + " event fired.");
   console.log("New option added!");  
}, false);


  // Now, you trigger the event when appropriate
  var opt = document.createElement("option");
  opt.textContent = "Choice 4";
  lst.appendChild(opt);  
  lst.dispatchEvent(event);
  
<select id="lstStuff">
  <option>Choice 1</option>
  <option>Choice 2</option>
  <option>Choice 3</option>
</select>
Scott Marcus
  • 60,351
  • 6
  • 44
  • 64
  • Nice and simple but I was looking for a way with out having to use dispatchEvent (or automate the call). It looks like I'll have to call it anyways like in @Zoltán Tamásis answer. This is good too! – Tinkle Pooplebottham Nov 21 '16 at 23:42
  • @TinklePooplebottham What's the problem with `dispatchEvent`? It's a native API and widely supported. – Scott Marcus Nov 22 '16 at 00:50
  • I didn't say anything was wrong with it. I was just thinking it was possible without having to call any methods to activate the listener. Like with a click event, I don't call a button.dispatchEvent(..). It already includes it. In my case, the moment I add an option to the lst, after the appending, I wouldn't call dispatchEvent. It would have been called automatically. As I said, you also gave a nice and clean solution. – Tinkle Pooplebottham Nov 22 '16 at 01:12
  • @TinklePooplebottham I guess I don't quite follow how you expected to have a custom event that didn't have to invoke your callback. Sure, you don't do that with button.click, but it is happening behind the scenes. – Scott Marcus Nov 22 '16 at 01:20
  • I was hoping to be able to do it behind the scenes. – Tinkle Pooplebottham Nov 22 '16 at 01:21
0

So I found exactly what I was looking for while browsing a javascript book!

Here is the magic:

var select = document.getElementById("slct");

var btn =  document.getElementById("btn");
btn.addEventListener("click", () => {
 var option = document.createElement("option");
 option.text = `${select.length} It works!`;
 select.add(option );
  //!!!select optionAdded event should have triggered!!!
});

select.addEventListener("DOMNodeInserted", () => {
 alert("Pow!");
});
<form>
  <select id="slct" style="width: 300px" mutiple="true" size="11">  
  </select>
  
  <button type="button" id="btn">click
  </button>
  
</form>