0

I have a set of inputs where I would like to add another input when the last input currently displayed receives focus. The form starts out with 2 inputs.

$('.answer_fields input:last-child').focus(function(event) {
        var nextfield = $('.answer_fields input').length + 1;
        $('.answer_fields').append('<input class="form-control answer_field" placeholder="Answer option #' + nextfield +'" id="answer' + nextfield +'">');
    });

As it currently stands, additional fields are only appended when the 2nd input (the original "last-child") receives focus.

Checking the source seems to show that the inputs are getting added to the DOM as expected. What am I missing?

Tai
  • 157
  • 1
  • 12

2 Answers2

3

The jQuery selector is evaluated ONCE at the time you run the code to install the .focus() event handler. It isn't adjusted live as things change. You can switch to event delegation if you want that type of behavior.

A similar event handler using event delegation that will be evaluated live would look like this:

$(some common parent selector).on("focus", ".answer_fields input:last-child", function() {
    // code here
});

Working demo: http://jsfiddle.net/jfriend00/ZZLPJ/


First off, your original code did not work because you were attaching event handlers to specific elements that existed at the time you ran your first code. Which events you had event handlers attached to did not change as your structure changed in the future so new elements would not have event handlers on them and the :last-child portion of your selector would not be re-evaluated.

Event delegation works because certain events that occur on a given element will bubble up the DOM hierarchy through each parent. You can attach a single event handler to a common parent and when that parent is notified that a given event occurred, it can then dynamically evaluate the selector you specified vs. the child item that originated the event and if it's a match, fire your event handler. This gives you the "real-time" selector evaluation that you want in your case.

To give you an idea, these are what I call "static" event handlers:

$(".test:last-child").focus(fn);
$(".test:last-child").on("focus", fn);

This a delegated (and thus dynamic) event handlers:

$("#parent").on("focus", ".test:last-child", fn);

For more info on this topic, see these other answers:

jQuery .live() vs .on() method for adding a click event after loading dynamic html

Does jQuery.on() work for elements that are added after the event handler is created?

Should all jquery events be bound to $(document)?

Just checked to be sure and the focus event does bubble event delegation will work with it.

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979
1

This is a common question for people starting to use jQuery. It turns out that the named eventListeners (i.e. $.fn.click, $.fn.focus, etc.) attach an event listener to each matching DOM element when the page is first loaded. These listeners are defined on the matching element themselves, meaning that each one is unique to the element it is attached to.

You will hear this method compared to what is commonly known as event delegation. Event delegation involves attaching an even listener to a shared parent element that will check the event.target attribute to see if it matches your criterion (in your case, .answer_fields input:last-child). This differs from attaching a unique listener to each DOM element you wish to target because it allows you to add new nodes to the DOM dynamically, which will then be handled by the parent node's listener like any other node.

To accomplish event delegation using jQuery, use the .on() function on a common ancestor (I'll use document as an example) and listen for all matching elements as the second argument of the function call:

$(document).on('focus', '.answer_fields input:last-child', function(event) {
    // your code here
});

Not only will this solve your problem with dynamically created DOM elements, but event delegation will greatly improve the performance of your page by reducing the total number of event listeners attached to elements in the DOM.

For more information about event delegation, I'd encourage you to check out this tutorial and this SO question

Community
  • 1
  • 1
wvandaal
  • 4,265
  • 2
  • 16
  • 27