web-dev-qa-db-fra.com

'observe' sur 'MutationObserver': le paramètre 1 n'est pas de type 'Node'

Je crée une extension Chrome et j'essaie d'inclure un petit texte à côté du bouton ENVOYER de la zone de composition de gMail.

J'utilise un MutationObserver pour savoir quand la fenêtre de composition apparaît. Je le fais en observant un élément avec la classe no puisque l'élément de composition est créé en tant qu'enfant de cet élément (classe no).

Lorsque l'utilisateur clique sur le bouton de composition et que la fenêtre de composition apparaît, je place un élément à côté du bouton ENVOYER à l'aide de la méthode .after(). Le nom de la classe du bouton SEND est .gU.Up.

Ce sont les vrais noms de classe de gMail et assez étranges aussi.

Ci-dessous le code que j'utilise:

var composeObserver = new MutationObserver(function(mutations){ 
    mutations.forEach(function(mutation){
        mutation.addedNodes.forEach(function(node){
            $(".gU.Up").after("<td> <div> Hi </div> </td>");
        });
    });
});

var composeBox = document.querySelectorAll(".no")[2];
var config = {childList: true};
composeObserver.observe(composeBox,config);

Le problème est que je reçois constamment l'erreur suivante:

Uncaught TypeError: Failed to execute 'observe' on 'MutationObserver': parameter 1 is not of type 'Node'

Quelqu'un peut-il aider? J'ai essayé pas mal de choses et j'ai aussi examiné d'autres réponses ici, mais je ne parviens toujours pas à supprimer cette erreur.

Voici mon manifest.json fichier:

{
    "manifest_version": 2,
    "name": "Gmail Extension",
    "version": "1.0",

    "browser_action": {
        "default_icon": "icon19.png",   
        "default_title": "Sales Analytics Sellulose"    
    },

    "background": {
        "scripts": ["eventPage.js"],
        "persistent": false
    },

    "content_scripts": [
    {
        "matches": ["https://mail.google.com/*"],
        "js": ["jquery-3.1.1.js", "insQ.min.js", "gmail_cs.js"]
    }
],

    "web_accessible_resources":[
        "compose_icon.png",
        "sellulosebar_icon.png" 
    ]
}

P.S. J'ai déjà essayé la bibliothèque insertionquery, mais elle présente quelques inconvénients. Cela ne me permet pas d’être précis quant aux modifications apportées à cet élément. Je n’ai pas encore essayé la bibliothèque de mutationsummary, mais comme elle utilise MutationObserver, j’ai pensé que le problème persisterait.

Ajouté du commentaire:
Il est vrai que le sélecteur ne me donne pas de noeud. J'ai vérifié dans la console, ça donne un objet. J'ai également vérifié dans la console et c'est sélectionner l'élément approprié que je veux être observé. 

Cependant, lorsque j'ajoute console.log pour l'élément sélectionné, il apparaît comme non défini. Ce qui signifie que vous avez probablement raison sur l’exécution du code avant l’apparition des nœuds. Pouvez-vous me dire comment vous assurer que le retard se produit? 'setTimeout' fonctionnera-t-il? Comment ça marche en cas de MutationObserver?

12
geet mehar

Comme je l'ai mentionné dans un commentaire et que Xan a donné une réponse, l'erreur indique clairement que le résultat de document.querySelectorAll(".no")[2] n'est pas évalué à un Node

D'après les informations que vous avez fournies dans un commentaire, il est clair que le problème est que le nœud que vous souhaitez observer n'existe pas lorsque votre code est exécuté. Il existe de nombreuses façons de retarder l'exécution de votre code jusqu'à ce que ce nœud soit disponible. Certaines possibilités sont:

  1. Utilisation d'une boucle setTimeout pour interroger jusqu'à ce que vous détectiez que l'élément sur lequel vous souhaitez placer le MutationObserver est disponible:

    function addObserverIfDesiredNodeAvailable() {
        var composeBox = document.querySelectorAll(".no")[2];
        if(!composeBox) {
            //The node we need does not exist yet.
            //Wait 500ms and try again
            window.setTimeout(addObserverIfDesiredNodeAvailable,500);
            return;
        }
        var config = {childList: true};
        composeObserver.observe(composeBox,config);
    }
    addObserverIfDesiredNodeAvailable();
    

    Cela trouvera le noeud approprié relativement peu de temps après son existence dans le DOM. La viabilité de cette méthode dépend du temps requis pour que l'observateur soit placé après l'insertion du noeud cible. De toute évidence, vous pouvez ajuster le délai entre les tentatives d’interrogation en fonction de vos besoins.

  2. Créez un autre MutationObserver pour surveiller un nœud ancêtre plus haut dans le DOM pour l'insertion du nœud sur lequel vous voulez placer votre observateur principal. Bien que le nœud approprié soit trouvé immédiatement après son insertion, il peut être très gourmand en ressources (processeur), en fonction de la hauteur dans le DOM que vous devez observer et du niveau d'activité associé aux modifications du DOM.
13
Makyen

Cette erreur signifie que document.querySelectorAll(".no")[2] n'est pas une Node.

Cela signifie très probablement qu'il n'y a pas un tel élément. querySelectorAll retournera toujours un NodeList, même s'il est vide; L'accès à des membres non existants de la liste réussit sans erreur d'exécution, mais renvoie undefined: en ce sens, NodeList agit comme un tableau.

"Attends, mais c'est le cas! Je lance ce code dans la console et cela fonctionne!" vous pouvez s'exclamer de façon dramatique. En effet, au moment où vous l'exécutez, longtemps après la fin du chargement du document, ces éléments existent.

Donc, vous devez attendre que cet élément racine soit ajouté; probable, avec un autre MutationObserver pour faire le travail.

3
Xan

Essayez d'utiliser ceci avec jQuery.

Si vous développez une extension Chrome et que vous obtenez un élément HTML (nœud) de la page ou du DOM dans le contenu_script , vous obtiendrez alors Object et le nœud seront renvoyés en tant que propriété de Object. Vous pouvez ensuite obtenir que le nœud de l'objet passe dans la méthode observe(Node,config).

Exemple

var node = $("#elementId");  //this is wrong because if you logged this in the console you will get Object

var node = $("#elementId")[0];  //This gives the first property of the Object returned, and this is correct because if you logged this in the console you will get the Node element for which you want to detect changes in the DOM.
1
Code Me