MutationObserver does not detect class addition

I have code like this:

Element.el
   (List.concat
       [ if tutorial.enabled then
           [ Element.Events.onClick (TutorialMsg (Tutorial.Current (Just Tutorial.Search1)))
           , Html.Attributes.id (Tutorial.idToString Tutorial.Search1) |> Element.htmlAttribute
           ]

           else
           []
       , case tutorial.current of
           Just current ->
               [ Html.Attributes.classList [ ( Tutorial.observeClass, current == Tutorial.Search1 ) ] |> Element.htmlAttribute ]

           Nothing ->
               []
       ]
   )
   (search isTutorialSearch1 window locale map state.search)

And such code for observer:

module.exports = {
    setup :
    function(app) {
        var containsObserver = app.ports.containsObserver_701aae30_0dc8_4bbf_9943_c5d1e28e6b07;
        var onContains = app.ports.onContains_3feaf185_0702_4f48_a011_ff932defa8df;
        var whatToObserve = document.body;
        if (containsObserver && onContains) {
            var portCallback = function(args) {
                var [ canaryId, className ] = args;
                var observer = new MutationObserver(function(mutations) {
                    console.log(mutations);
                    var elems = document.getElementsByClassName(className);
                    for(var i = 0; i < elems.length; i++) {
                        console.log(elems[i].id);
                        // onContains.send(elems[i].id);
                    }
                    mutations.forEach((mutation) => {

                        if (mutation.type == "childList" && mutation.addedNodes.length > 0) {
                            mutation.addedNodes.forEach(processNode);
                        } else if (mutation.type == "attributes") {
                            console.log(mutation);
                            processNode(mutation.target);

                            if (mutation.target.id == canaryId) {
                                clearInterval(intervalID);
                                mutation.target.remove();
                            }
                        }

                        function processNode(node) {
                            if (node.classList && node.classList.contains(className)) {
                                onContains.send(node.id);
                            }

                        }
                    });
                });

                observer.observe(whatToObserve, {attributes: true, attributeFilter: ['class'], childList: true, characterData: false, subtree:true});

                var newDiv = document.createElement("div");
                newDiv.id = canaryId
                whatToObserve.appendChild(newDiv);
                var intervalID = window.setInterval(() => newDiv.classList.toggle(className), 500);
            };
            containsObserver.subscribe(portCallback);
        }
    }
};

If I run two times this in devconsole:

document.getElementById("Search1").classList.toggle(observeClass)

I will get notification from observer.

Tested both in Firefox and Chrome.

Here Race Condition? Fetching an element by ID of a view which is yet to be rendered it is adviced to use MutationObserver. Now I am not so sure about it.

Also there are answers on so to better use getElementById setTimeout bc observing document.body may be to slow.

So my question is: does anybody experienced this? How to overcome it?

Hello @rofrol,

You’ve created your post under “Learn”. From it’s content it is not entirely clear what you would like to learn. What is your question exactly?

I’ve added question.