Check if Node created with insertAdjacentHTML in a loop is "visible"

0

I'm looking for fragments of HTML with fetch() and adding to DOM with function insertAdjacentHTML() in loop for() ... the function that performs this task is in Promise() and its% return (in case of success) use another function to modify the content of parts of the document that contain a certain attribute.

The following example is true:

let fragments = [
    {
       file: "navbar.html",
       mode: "prepend",
       target: "#body"
    },
    {
       file: "modal-cookies.html",
       mode: "insertAfter",
       target: ".drawer-menu"
    },
    {
       file: "footer.html",
       mode: "append",
       target: "#body"
    }
]

//
const __DEFINE__ = () => {
    return new Promise((resolve, reject) => {

        let urls = [],
            param = [],
            len = fragments.length

        for (let i = 0; i < len; i++) {
             urls.push(fragments[i].file);
             param.push({
                 mode: fragments[i].mode,
                 target: fragments[i].target
             })
        }

        let fetchResource = (url, i) => {
            return fetch(url).then(response => {
                if ( response.ok ) {
                    return response.text()
                }
                return Promise.reject()
            }).then(text => {
                return text
            }).catch(e => {
                return Promise.reject(e)
            })
        }

        Promise.all(urls.map(fetchResource)).then(response => {

            for (let i = 0; i < response.length; i++) {
                 let target = document.querySelector(param[i].target)
                 switch (param[i].mode) {
                     case 'insertBefore':
                        target.insertAdjacentHTML('beforebegin', response[i])
                     break
                     case 'insertAfter':
                        target.insertAdjacentHTML('afterend', response[i])
                     break
                     case 'append':
                        target.insertAdjacentHTML('beforeend', response[i])
                     break
                     case 'prepend':
                        target.insertAdjacentHTML('afterbegin', response[i])
                     break
                 }
            }
            // após processar o loop "resolver"
            resolve()
        }).catch(e => {
            reject(e)
        })
    })
}

//
__DEFINE__().then(() => {
    // manipular o DOM após ter adicionado novos Node's
    let allTargets = document.querySelectorAll('.uma-classe')
    [...allTargets].forEach(item => {
        //
        item.innerHTML = 'Exemplo'
    })
}).catch(e => {
    console.error(e)
})

Apparently the loop was processed and new "Node's" were added to DOM bad when running the function that modified parts of these new elements sometimes when loading the page "it seems" that the "Node's" did not finish being accommodated to the DOM and consequently the changes are not performed.

Within Promisse.all() how would you check if these "Node's" were completely added to DOM ?

    
asked by anonymous 28.01.2018 / 18:51

1 answer

0

Not long after asking I came to a satisfactory logic ... a shame to delay sharing the result here, but it's never late.

  

In the heart of the matter

Initially I was marking classes throughout the document to map them with querySelector and "translate" following a set of words in a JSON object (a "dictionary").

This made me import the JSON (fetch) at the beginning of the script, traverse the document and add the corresponding words based on their respective indexes obtained from a data - attribute, something like this:

<a href="/contact" data-i18n-html="navbar.contact" class="i18n"></a>
Rather, some "fragments" of documents were added dynamically (fetch) which forced me to cross the document again to redo everything again ... it was costly, logically unnecessary and presenting some errors that I was not able to handle. The question mentions the most serious of these errors.

  

The alternative

I needed to add a property called "translated=" true " to the elements found in the" first round "passed through the document and # for the iterated items of the result of Promise.all (text) and added to the document (nodes), this allowed me to iterate over just these nodes and all of its underlying descendants with the i18n class that did not (yet) contain the translated property without having to traverse the entire document again and again has ensured that all these elements are now "translated".

  

The result

The substantial part that changed was exactly this:

// utilidades
const UTILS = {
    objectToString(o) {
        return Object.prototype.toString.call(o)
    },
    type(obj) {
        return (obj) ? UTILS.objectToString(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase() : 'undefined'
    }
}
// MutationObserver
let SpyDOM = (node, callback, options) => {
    let observer = new MutationObserver(callback)
    observer.observe(node, options)
}
// request resource
Promise.all(urls.map(fetchResource)).then(response => {
    response.forEach((item, i, array) => {
        // refuse "undefined"
        if ( item ) {
            let target = documento.querySelector(param[i].target)
            // initialize MutationObserver
            SpyDOM(target, mutations => {
                mutations.forEach(mutation => {
                    ;[...mutation.addedNodes].forEach(addedNode => {
                        if ( /element/g.test(UTILS.type(addedNode)) ) {
                            ;[...addedNode.querySelectorAll('[class^="i18n"]:not([translated])')].forEach(node => {
                                // "traduzir" este Node
                                funcao_traduzir(node)
                            })
                        }
                    })
                })
            }, {childList: true})
            switch (param[i].mode) {
                case 'insertBefore':
                    target.insertAdjacentHTML('beforebegin', item)
                break
                case 'insertAfter':
                    target.insertAdjacentHTML('afterend', item)
                break
                case 'append':
                    target.insertAdjacentHTML('beforeend', item)
                break
                case 'prepend':
                    target.insertAdjacentHTML('afterbegin', item)
                break
            }
        }
        // if last item
        if ( i === array.length -1 ) {
            resolve()
        }
    })
}).catch(e => {
    reject('e')
})

I thought about closing this question but, I leave this answer for reference who knows help someone.

    
17.08.2018 / 06:30