0

Here is the HTML part:

<div class="toggle-3">
    <a href="#" class="deploy-toggle-3"> More Details
        <em>
            <strong></strong>
        </em>
    </a>
    <div class="toggle-content">
        <p>Text Here</p>
    </div>
</div>

When you click on More Details, the HTML changes to this:

<div class="toggle-3">
    <a href="#" class="deploy-toggle-3"> More Details
        <em class="toggle-3-active-background">
            <strong class="toggle-3-active-ball"></strong>
        </em>
    </a>
    <div class="toggle-content" style="display: block;">
        <p>Text Here</p>
    </div>
</div>

This happens because I use a script that includes this code (let's call it toggle-script for future reference):

$(".deploy-toggle-3").click(function() {
    $(this).parent().find('.toggle-content').slideToggle(200);
    $(this).find('em strong').toggleClass('toggle-3-active-ball');
    $(this).find('em').toggleClass('toggle-3-active-background');
    return false;
});

So far so good. Now, for various reasons, I want to make an AJAX call and update the HTML. I do this using the following script:

function createHTML() {
    let content = 
        ' <div class="container"> ' +
        ' <div class="toggle-3"> ' +
        ' <a href="#" class="deploy-toggle-3">{14} ' +
        ' <em><strong></strong></em></a> ' +
        ' <div class="toggle-content"> ' +
        ' <p>{15}</p> ' +
        ' </div> ' +
        ' </div> '
    ;

    return content.format(
        // In here I replace the {14} and {15} with what I want
    );
}

let my_content = createHTML();

$("#my-container").html(my_content);

While it does replace the HTML correctly, I have noticed that it removes the Event Listener from the More Details element. This means that, if you click on it, it does not run the toggle-script. Reading the JQuery DOC, I found this:

jQuery removes other constructs such as data and event handlers from child elements before replacing those elements with the new content.

My temporary fix is to re-include the toggle-script after running the .html() function.

1) Can someone explain if what I described is the case indeed? Or what exactly is going on?

2) Is there a way to deal with this more effectively than my temporary solution? Ideally, a way to not remove the Event Listeners in the first place.

3) Is the way I am updating the HTML optimal? Is there a better way to do this and why?

padawanTony
  • 1,046
  • 2
  • 20
  • 34
  • 1
    It doesn't remove the event handler - there never was one on the new elements you create. When dealing with events on dynamic content it's best to use delegated event handlers. The duplicate I've marked shows you exactly how to do this – Rory McCrossan Mar 31 '20 at 14:55
  • 1
    Why not just update the content of the `toggle-content` element and simply update class names on the `toggle-3` element to update the styles? Essentially you are completely replacing the `toggle-3` element, so any event listeners attached elsewhere would be destroyed. – Kevin Boucher Mar 31 '20 at 14:56
  • I see. Thank you both. – padawanTony Mar 31 '20 at 16:46
  • @RoryMcCrossan what about a case in which you import a script that attaches the event handlers to the elements? Let's say you use a template you found/bought online. This script will be responsible for many things in your code. Is the only option you have to hunt down inside the script the parts of code that were previously assigned to your old elements before you dynamically re-create them? – padawanTony Apr 01 '20 at 16:26
  • 1
    It's not the only solution, but it's by far the best one – Rory McCrossan Apr 01 '20 at 17:15

0 Answers0