0

I have tabs containing accordions containing buttons. After switching between tabs the buttons no longer trigger their click event. I have abstracted my code below and I have checked with logs that refreshBehaviours() is always called after the buttons are rendered. Why is the event not triggering as expected?

    $( window ).load(function() {
        googleMapScript.addEventListener('load',() => {

            // Tabs functionality
            $('body').on('click', '.tablinks', function() {
                // Declare all variables
                var i, tabcontent, tablinks;              
                // Get all elements with class="tabcontent" and hide them
                tabcontent = document.getElementsByClassName("tabcontent");
                for (i = 0; i < tabcontent.length; i++) {
                    tabcontent[i].classList.remove('active');                        
                }              
                document.getElementById('tab-'+this.getAttribute('category')).classList.add("active");
                // Get all elements with class="tablinks" and remove the class "active"
                tablinks = document.getElementsByClassName("tablinks");
                for (i = 0; i < tablinks.length; i++) {
                    tablinks[i].classList.remove('active');
                }              
                this.classList.add("active");
                // hide toggleable categories that are not of this tab
                for (var category in self.categories) {
                    if (category != this.getAttribute('category') && self.categories[category].toggles) {
                        self.hideCategory(category)
                    }
                }
                // show this category
                markerList.showCategory(this.getAttribute('category'))              
                console.log('refreshed behaviour')                              
            })

            // Accordion functionality
            $('body').on('click', '.accordion', function(){

                /* Toggle between adding and removing the "active" class,
                to highlight the button that controls the panel */
                this.classList.toggle("active");            

                /* Toggle between hiding and showing the active panel */
                var panel = this.nextElementSibling
                panel.classList.toggle("active");                

                var category = this.getAttribute('category')
                var marker = this.getAttribute('marker')                
                if (this.classList.contains('active')) {
                    new google.maps.event.trigger(markerList.categories[category].markers[marker], 'mouseover')
                    if (markerList.startPoint != 0) { 
                        markerList.categories[category].markers[marker].getDistance(markerList.startPoint).then(function(data){
                            var data = data.rows[0].elements[0]        
                            panel.innerHTML = panel.innerHTML+               
                            '<hr>Avstånd '+data.distance.text+'<br/>Resa med '+markerList.transporation+': '+data.duration.text                        
                        })  
                    }                  
                } else {
                    new google.maps.event.trigger(markerList.categories[category].markers[marker], 'mouseout')
                    panel.innerHTML = markerList.categories[category].markers[marker].template[0]
                }

                // find and load in any images in templates designated by the load-image class
                var images = panel.getElementsByClassName('load-image');
                for (var i = 0; i <= images.length-1; i++) {
                    images[i].innerHTML = '<img src="'+images[i].getAttribute('path')+'"/>'
                }    

                // attach expand button if we don't already have one
                if (panel.getElementsByClassName("select-marker").length == 0 && panel.getElementsByClassName("expand-marker").length == 0) {
                    if (markerList.startPoint == 0) {                    
                        panel.innerHTML = panel.innerHTML+`<button class="select-marker" category="${category}" marker="${markerList.categories[category].markers[marker].id}">Välj annons</button>`
                    } else {
                        panel.innerHTML = panel.innerHTML+`<button class="expand-marker" category="${category}" marker="${markerList.categories[category].markers[marker].id}">Läs mer</button>`
                    }                       
                    console.log('refreshed behaviour')
                }                                                                           
            })


            // functionality for generated buttons in accordions
            $('body').on('click', '.select-marker', function(){
                new google.maps.event.trigger(self.categories[this.getAttribute('category')].markers[this.getAttribute('marker')], 'click')
            })
            $('body').on('click', '.expand-marker', function(){
                this.parentElement.innerHTML = self.categories[this.getAttribute('category')].markers[this.getAttribute('marker')].template[1]
                new google.maps.event.trigger(self.categories[this.getAttribute('category')].markers[this.getAttribute('marker')], 'mouseover')
            })
        })              

    })

HTML structure

<div id="list">
    <div id="tablist">
        <button class="tablinks">A tab link</button>
    </div>
    <div id="tab-id" class="tabcontent">
        <button class="acccordion">An accordion</button>
        <div class="panel">
            <button class="select-marker">This button dosent trigger if another tab is opened</button>
        </div>
    </div>
</div>
FroboZ
  • 437
  • 1
  • 6
  • 17
  • 1
    Can you add the relevant HTML to the question. Also note that the entire point of delegated event handlers is that they are added before the elements, so remove the `refreshBehaviours()` function and put the `on()` handler it contains in the same scope as the others. In addition you can use jQuery's `next()` and `append()` instead of `nextElementSibling` and manually concatenating to `innerHTML` – Rory McCrossan Apr 02 '20 at 13:59
  • Add your HTML as well – Alok Mali Apr 02 '20 at 14:01
  • I had it set up like that before, it was an answer from another question that was similar to mine that suggested using this so that the eventhandlers are fefreshed when new elements are added dynamically. I will add the HTML structure as you requested. – FroboZ Apr 02 '20 at 14:02
  • @ChristopherKarlsson, actually `.on` is a live event. If you use this you don't need to apply it again for dynamically created elements. It works with default initialization. – Alok Mali Apr 02 '20 at 14:04
  • Maybe you have another issue. – Alok Mali Apr 02 '20 at 14:05
  • @AlokMali I agree, it was suggested here https://stackoverflow.com/questions/1359018/how-do-i-attach-events-to-dynamic-html-elements-with-jquery by Chandler Zwolle – FroboZ Apr 02 '20 at 14:09
  • The HTML structure has been added. The buttons work fine as long as the tabs aren't switched. The tab content that are not shown are simply display: none, they are not removed from the Dom. This is handled by toggling an active class. Same for accordions. Displayed if they have .active otherwise not. – FroboZ Apr 02 '20 at 14:10
  • @RoryMcCrossan Thank you, I'll be using next, append is not an option as it can be triggered multiple times so I would end up with more buttons. This was originally vanilla JS and I implemented jQuery on becuase I could not get the vanilla events to work. – FroboZ Apr 02 '20 at 14:14
  • 1
    Fair enough, but be aware that your current logic will also have the same problem – Rory McCrossan Apr 02 '20 at 14:15
  • @RoryMcCrossan Ah yes, sorry its been a long day of coding, previously I was not reappending the innerHTML but overwriting it with a loaded template so this was not an issue but I agree that now it is and thats something else I'll have to fix. – FroboZ Apr 02 '20 at 14:27

0 Answers0