14

I have an issue when I use jQuery to handle the trigger of change on my drop-down.

I use 2 pieces of code:

//---------- Case 1
$(document).on("change", "#drop-down-id", function () {
    alert(this.value);
});
//----------Case 2
$("#drop-down-id").change(function () {
    alert(this.value);
});

The first one running smoothly, but the second one is not triggered when I start the browser, but after I refresh my site, it works.

Do you have any idea?

My jQuery version: 1.11.1, and I've tested on Chrome 38, Firefox 32 and IE 11.

-- Edit: @JanR & Cheery: It seems like this:

<select id="drop-down-id">
    <% arr.each do |option| %>
        <option value="<%= option %>"><%= option %></option>
    <% end %>
</select>

I've used Rails 4.1 and arr is an array contains numbers.

-- Edit: I found out that the issue came from the Asset Pipeline of Rails, not the jQuery.

I put the JS code inside a script tag and it works in both case, but when I put it in the assets folder, the issue happens.

Thank you for your quick replies!

haitran
  • 665
  • 1
  • 5
  • 19
  • 2
    Can you reconstruct the problem at, let say, jsfiddle.net? Does this select created dynamically or not? – Cheery Oct 28 '14 at 02:25
  • 2
    case 1 can be used to elements even if your element still not exists in the html. case 2 should be used inside the dom ready function to work, so that all elements in the html are loaded. – roullie Oct 28 '14 at 02:27
  • @Cheery, yes the select created dynamically. I haven't use jsfiddle.net yet, :), so let me try it! – haitran Oct 28 '14 at 02:33
  • @roullie, you mean that in case 2, the dom hasn't loaded yet? – haitran Oct 28 '14 at 02:33
  • 1
    @haitran `yes the select created dynamically.` it means, probably, that at the moment of the listener assignment it does not exists. With refresh browser reads from cache and select on its place almost instantly. You should call `.change(` when element already exists. – Cheery Oct 28 '14 at 02:34
  • @haitran yes that is possible. use case 2 like JanR showed below and it would work. – roullie Oct 28 '14 at 02:35
  • @Cheery I've used _$(document).ready_, but it still not work, any idea? – haitran Oct 28 '14 at 02:47
  • @haitran can not tell without seeing the whole code, not just a portion of it. – Cheery Oct 28 '14 at 02:48
  • your case 1 is working because it is pointing on your whole document and your control maybe loaded dynamically. – mhars Oct 28 '14 at 02:58
  • 2
    In the future, for a question related to HTML/JavaScript, your server-side language is of no consequence. You want to show people the same code that the browser sees, i.e. the HTML produced by the server. However, a tiny snipped of just a ` – Phrogz Oct 28 '14 at 03:12
  • 1
    P.S. In HTML, if you want the value of an option to be the same as what it displays, you do not need a `value="…"` attribute. – Phrogz Oct 28 '14 at 03:13
  • @Phrogz Thanks, in my real project, I've used other value for the option! I will try the pared-down as you said! – haitran Oct 28 '14 at 03:23

3 Answers3

6

I recommend using case 1, since it is composed document to load change event, if you choose the elements are dynamically generated, use case 1 will be effective.

Also jquery doc said, .change () is a shortcut for .on ("change", handler), so I think eventually will use .on callback.

Lion
  • 81
  • 1
  • 6
  • 1
    Yes, I've used Case 1 in my project, but as you said (and also in the jQuery document), _.change () is a shortcut for .on ("change", handler)_, so what is the different? – haitran Oct 28 '14 at 02:44
  • As the final callback .on, so I think there will be performance advantages; the other maybe removed, like .live – Lion Oct 28 '14 at 03:22
2

When using .on(), keep in mind that:

  • Case 2, is an alias: .change(...) === .on("change", handler) - If the selector is omitted or is null, the event handler is referred to as direct or directly-bound (The handler is called every time an event occurs on the selected elements). In this case, if you want to bind something successfully to an element, you need to ensure it is already loaded.

  • Case 1: .on("change", selector, handler) - If the selector is provided, the event handler is referred to as delegated (The handler is not called when the event occurs directly on the bound element, but only for descendants that match the selector). In this case, you don't need the element to be loaded or not at the time of your binding.

The benefits of doing it one way instead of the other are well explained in this answer from Difference between .on('click') vs .click().

ajax333221
  • 10,585
  • 14
  • 56
  • 89
1

In case one you are binding the change event on the document level to an element that's part of the document. At this stage it doesn't matter whether it exists or not yet (say it's created later or loaded later).

In the second case you are binding the event to an element that has to exist in the DOM already or the binding will fail. What can be happening is that your javascript is firing before the element has been loaded on the page.

Try wrapping case 2 in a $(document).ready() function like so:

$(document).ready(function(){
//----------Case 2
        $("#drop-down-id").change(function () {
              alert(this.value);
        });
});

This will ensure your javascript won't fire until the DOM is ready.

JanR
  • 5,834
  • 2
  • 20
  • 30
  • Can you post your html etc? It's really hard to troubleshoot otherwise as it depends on how you are generating the page. If you are dynamically adding the object I would recommend you use case 1. – JanR Oct 28 '14 at 02:45
  • As pointed out the in the comments we would neeed to see more than that, is there any other javascript running on the page? What does the DOM structure look like etc. – JanR Oct 28 '14 at 03:13
  • no, thats .on("change", callback) and .on("change","parent", callback) the second one deals with event delegation. – argentum47 Oct 28 '14 at 07:53
  • This is a REALLY useful answer and will ensure you consider how the on change event is applied within the DOM or document, thanks JanR – Stan Howe May 25 '20 at 20:03