HTMLSnippet Jquery only works for one page, on the first load

0
Hi all, Myself and a colleague are getting a bit stumped with a jquery problem in our app. We have a number of pages that use List views to show data. Each entry shows a styled block, and we want a JS action to trigger every time a user clicks on a button, to dropdown a block below it with some more information The function, we're including in a HTMLSnippet; $('.accordian-button').click(function(){ $(this).toggleClass('fa-arrow-down fa-arrow-up'); $(this).closest('.brick-body').siblings('.brick-expand').toggleClass('details-not-visible details-visible '); }); When we load our first page in with this function in the page, it works fine. However, if we navigate away to another page with this function, or away then back to the same page, it stops working entirely. No class toggle, so no style change. Has anyone encountered this problem before, any workarounds? Cheers Luke
asked
2 answers
5

Hi Luke,

You should really avoid using jQuery in mendix apps in such manner. Mendix loads pages and data dynamically which means that when this particual jquery code is run (which you have no control over) there is no guarantee that the elements you are trying to select will be in the DOM. Also Mendix dynamically replaces DOM nodes  when the page or objects within the page is refreshed.

If you use case is to set some classes on click try the widget - https://appstore.home.mendix.com/index3.html in combination with a microflow that refreshes the object for the user

Alternatively try to emulate the bahaviour that you are looking for by using conditional visibility.

Hope this helps,

-Andrej

PS: If you have no other options left, you can wrap your code in a setTimeout and call it every 50-100ms. This will very work, but I wouldn't use it except perhaps for making a demo.

var f = function(millis) {
 $('.accordian-button').click(function(){
    $(this).toggleClass('fa-arrow-down fa-arrow-up');
    $(this).closest('.brick-body').siblings('.brick-expand').toggleClass('details-not-visible details-visible ');   
 });
 setTimeout(function () {f(millis);},millis);
}

f(100);
answered
3

As Andrej states, it's best to avoid jQuery. But, if you are using it, you should make the click use dynamic elements. The point here is that the element might not have been created yet. So it should be written as:

$(document).on('click', '.accordian-button', function(){
    $(this).toggleClass('fa-arrow-down fa-arrow-up');
    $(this).closest('.brick-body').siblings('.brick-expand').toggleClass('details-not-visible details-visible ');   
});

Although this might work, there is one caveat....

If you move away from the page, the element might have been removed, your HTML widget might have been removed, but the event listener above might still be there. This means that you add additional event listeners while not removing the old ones.

I did something similar for a partner project, where you basically connect to the button widget. This way the event listener is removed after the button is removed:

var identifier = '.languageButton';

// We use this to make sure jQuery is loaded
$(function () {
    var $buttonEls = $(identifier);

    if ($buttonEls) {
        $buttonEls.each(function () {
            var $this = $(this);
            var buttonWidget;

            try {
                buttonWidget = dijit.registry.byNode($this.get(0));
            } catch (e) {
                console.error('Cannot find widget with class: ' + identifier);
            }

            if (buttonWidget) {
                buttonWidget.connect(buttonWidget, 'onAfterAction', function () {
                    // Do your thing here!
                });
            } else {
                console.log('Cannot find widget for', $this);
            }
        })
    }
});

This only works with Mendix buttons that are added to the page and will only work with buttons that are not conditional visible.

answered