0

I have a Javascript script in which I define a class called a "Layer". I put code in the Layer constructor, so that each time a new Layer object is created a checkbox associated with that layer is added to the HTML document. I also created a JQuery event handler within the constructor so that when the new checkbox is clicked, the layer is either shown or hidden within the document depending on the state of the checkbox. For some reason however, the event handler only works for the most recently created layer. Somehow the old event handlers are getting overwritten. I searched on here for similar questions, and saw that using the on function from JQuery rather than click is the way to go, but I'm still having the same issue. Here's my code...

Layer2D.prototype.addToUI = function() {
    if (this.firstLayer()) {
        var layerDiv = document.createElement('div');
        layerDiv.className = 'content';
        layerDiv.id = 'layerNames';
    }
    else {
        var layerDiv = document.getElementById('layerNames');
    }

    layerDiv.innerHTML += '</br>' +
                          '<div class="ui toggle mini checkbox" id="layer' + this.name +'">' +
                          '<input type="checkbox" name="' + this.name + '" checked>' +
                          '</input>' +
                          '<label>' + this.name + '</label>' +
                          '</div>';

    if (this.firstLayer()) {
        var parentDiv = document.getElementById('layerMenu');
        parentDiv.appendChild(layerDiv);
    };
    $('#layer' + this.name).after('<br/>');

    var This = this;
    $('#layer' + this.name).on('click', ':input', function(e) {
        checked = $(this).is(':checked');
        console.log(This);
        if (checked === true) {
            This.show();
        }
        else { 
            This.hide();
        }
    });
};
Danny
  • 384
  • 1
  • 5
  • 16
  • Possible duplicate of [Event binding on dynamically created elements?](http://stackoverflow.com/questions/203198/event-binding-on-dynamically-created-elements) – Heretic Monkey Aug 02 '16 at 22:47
  • @MikeMcCaughan I don't think so. The solution there was to use the JQuery `on()` method which I'm already using here. – Danny Aug 02 '16 at 23:04
  • Please read the full answer. It talks about event delegation, using three arguments to `on`. – Heretic Monkey Aug 02 '16 at 23:17
  • I did but I still only have a vague idea of how it applies here. I think my issue (which from the answers appears to be with innerHTML) is different enough from the one in that question to warrant its own post. – Danny Aug 02 '16 at 23:31

3 Answers3

1

You should use $(document).on('click', '#layer' + this.name, function(){...}) it usually works with dynamically added HTML.

ramongr
  • 57
  • 4
  • Great, this works for me! I guess the key was calling the `on()` method on the document object itself rather than on the checkbox. Still not sure why one way would work and the other wouldn't though. – Danny Aug 02 '16 at 23:19
  • A short/simple explanation would be that js only knows about what already exists with the attribute filter you've set. If you want js to about more than that you need to broaden it's scope, so it can find your newly created elements. – ramongr Aug 03 '16 at 10:52
0

innerHTML has this issue. If you create the dynamic elements using Document.create methods, I think the listener will be attached. In any case you can put your evenListener(s) in a function like addEventListenerToBeer() and call it after the innerHTML call.

var d = document.createElement("div")
var t = document.createTextNode("i like beer");
d.id = "myId";
d.appendChild(t); 
Ronnie Royston
  • 16,778
  • 6
  • 77
  • 91
  • Thanks, I think you're right about the issue being with `innerHTML`. I'm pretty sure your fix would work, but the above solution is a bit simpler. Thank you for your help though! – Danny Aug 02 '16 at 23:33
  • Also, now I'm tempted to id all my div elements with names of different IPAs. – Danny Aug 02 '16 at 23:33
0

You need to replace:

layerDiv.innerHTML += '</br>' +
                      '<div class="ui toggle mini checkbox" id="layer' + this.name +'">' +
                      '<input type="checkbox" name="' + this.name + '" checked>' +
                      '</input>' +
                      '<label>' + this.name + '</label>' +
                      '</div>';

for:

let element="";
//****
element = '</br>' +
                      '<div class="ui toggle mini checkbox" id="layer' + this.name +'">' +
                      '<input type="checkbox" name="' + this.name + '" checked>' +
                      '</input>' +
                      '<label>' + this.name + '</label>' +
                      '</div>';
$(element).appendTo(layerDiv);

appendTo inserts the elements and make them part of the DOM to be query...

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
DIEGO CARRASCAL
  • 1,999
  • 14
  • 16
  • OK thanks, I never would've guessed that this was an innerHTML issue. Your solution sort of works, but in this case the whole innerHTML is duplicated each time a new checkbox is added. – Danny Aug 02 '16 at 23:13
  • yes you are right, it doesn't need the `elements=layerDiv.innerHTML;` sorry about that... I'll update my answer... – DIEGO CARRASCAL Aug 03 '16 at 12:14