Quelles sont les raisons possibles document.getElementById
, $("#id")
ou toute autre méthode DOM / sélecteur jQuery ne trouvant pas les éléments?
Exemples de problèmes:
- jQuery échoue silencieusement à lier un gestionnaire d'événements
- jQuery méthodes "getter" (
.val()
,.html()
,.text()
) retourundefined
- Une méthode DOM standard renvoyant
null
entraînant l'une des erreurs suivantes:
TypeError non capturé: impossible de définir la propriété «...» de null TypeError non détecté: impossible de lire la propriété «...» de null
Les formes les plus courantes sont:
TypeError non capturé: impossible de définir la propriété «onclick» de null
TypeError non capturé: impossible de lire la propriété 'addEventListener' de null
TypeError non capturé: impossible de lire la propriété 'style' de null
javascript
jquery
dom
Felix Kling
la source
la source
Réponses:
L'élément que vous tentiez de trouver n'était pas dans le DOM lors de l' exécution de votre script.
La position de votre script DOM-dépendant peut avoir un effet profond sur son comportement. Les navigateurs analysent les documents HTML de haut en bas. Des éléments sont ajoutés au DOM et les scripts sont (généralement) exécutés lorsqu'ils sont rencontrés. Cela signifie que l'ordre est important. En règle générale, les scripts ne peuvent pas trouver des éléments qui apparaissent plus tard dans le balisage car ces éléments doivent encore être ajoutés au DOM.
Considérez le balisage suivant; le script n ° 1 ne parvient pas à trouver le
<div>
script n ° 2 réussit:Alors, que devrais-tu faire? Vous avez quelques options:
Option 1: déplacer votre script
Déplacez votre script plus bas dans la page, juste avant la balise de fermeture. Organisé de cette manière, le reste du document est analysé avant l'exécution de votre script:
Remarque: Le placement de scripts en bas est généralement considéré comme une meilleure pratique .
Option 2: jQuery
ready()
Reportez votre script jusqu'à ce que le DOM soit complètement analysé, en utilisant :
$(handler)
Remarque: Vous pouvez simplement vous lier à
DOMContentLoaded
ou mais chacun a ses mises en garde. jQuery propose une solution hybride.window.onload
ready()
Option 3: délégation d'événement
Lorsqu'un élément déclenche un événement (à condition qu'il s'agisse d'un événement bouillonnant et que rien n'arrête sa propagation), chaque parent de l'ascendance de cet élément reçoit également l'événement. Cela nous permet d'attacher un gestionnaire à un élément existant et d'exemples d'événements au fur et à mesure qu'ils remontent de ses descendants ... même ceux ajoutés après que le gestionnaire est attaché. Tout ce que nous avons à faire est de vérifier l'événement pour voir s'il a été déclenché par l'élément souhaité et, si c'est le cas, d'exécuter notre code.
jQuery's
on()
exécute cette logique pour nous. Nous fournissons simplement un nom d'événement, un sélecteur pour le descendant souhaité et un gestionnaire d'événements:Remarque: En règle générale, ce modèle est réservé aux éléments qui n'existaient pas au moment du chargement ou pour éviter d'attacher une grande quantité de gestionnaires. Il convient également de noter que même si j'ai attaché un gestionnaire à
document
(à des fins de démonstration), vous devez sélectionner l'ancêtre fiable le plus proche.Option 4: l'
defer
attributUtilisez l'
defer
attribut de<script>
.Pour référence, voici le code de ce script externe :
Remarque: l'
defer
attribut semble certainement être une solution miracle, mais il est important d'être conscient des mises en garde ...1.
defer
ne peut être utilisé que pour des scripts externes, c'est-à-dire ceux qui ont unsrc
attribut.2. soyez conscient de la prise en charge du navigateur , c'est-à-dire: implémentation de buggy dans IE <10
la source
<head>
et utiliser desdefer
scripts (je n'ai pas à supporter de mauvais vieux navigateurs incompatibles)defer
etasync
ont un support assez large, allant même jusqu'à des versions de navigateur beaucoup plus anciennes. Ils ont l'avantage supplémentaire de signaler clairement et explicitement le comportement souhaité. N'oubliez pas que ces attributs ne fonctionnent que pour les scripts spécifiant unsrc
attribut, c'est-à-dire les scripts externes. Pesez les avantages. Peut-être utiliser les deux? Ton appel.Bref et simple: car les éléments que vous recherchez n'existent pas (encore) dans le document.
Pour le reste de cette réponse, je vais utiliser
getElementById
comme exemple, mais la même chose s'applique àgetElementsByTagName
,querySelector
et à toute autre méthode DOM qui sélectionne des éléments.Raisons possibles
Il existe deux raisons pour lesquelles un élément peut ne pas exister:
Un élément avec l'ID transmis n'existe vraiment pas dans le document. Vous devez vérifier que l'ID que vous transmettez
getElementById
correspond vraiment à l'ID d'un élément existant dans le code HTML (généré) et que vous n'avez pas mal orthographié l'ID (les ID sont sensibles à la casse !).Par ailleurs, dans la majorité des navigateurs contemporains , qui implémentent
querySelector()
etquerySelectorAll()
méthodes, la notation de style CSS est utilisée pour récupérer un élément par sonid
, par exemple:,document.querySelector('#elementID')
par opposition à la méthode par laquelle un élément est récupéré par sonid
sousdocument.getElementById('elementID')
; dans le premier le#
caractère est essentiel, dans le second il conduirait à ce que l'élément ne soit pas récupéré.L'élément n'existe pas au moment où vous appelez
getElementById
.Ce dernier cas est assez courant. Les navigateurs analysent et traitent le HTML de haut en bas. Cela signifie que tout appel à un élément DOM qui se produit avant que cet élément DOM n'apparaisse dans le HTML, échoue.
Prenons l'exemple suivant:
Le
div
apparaît après lescript
. Au moment où le script est exécuté, l'élément n'existe pas encore etgetElementById
reviendranull
.jQuery
La même chose s'applique à tous les sélecteurs avec jQuery. jQuery ne trouvera pas d'éléments si vous avez mal orthographié votre sélecteur ou si vous essayez de les sélectionner avant qu'ils n'existent réellement .
Une torsion supplémentaire se produit lorsque jQuery est introuvable car vous avez chargé le script sans protocole et exécutez à partir du système de fichiers:
cette syntaxe est utilisée pour permettre au script de se charger via HTTPS sur une page avec le protocole https: // et de charger la version HTTP sur une page avec le protocole http: //
Il a le malheureux effet secondaire de tenter et de ne pas charger
file://somecdn.somewhere.com...
Solutions
Avant d'appeler
getElementById
(ou toute méthode DOM d'ailleurs), assurez-vous que les éléments auxquels vous souhaitez accéder existent, c'est-à-dire que le DOM est chargé.Cela peut être assuré en plaçant simplement votre JavaScript après l'élément DOM correspondant
dans ce cas, vous pouvez également mettre le code juste avant la balise de fermeture du corps (
</body>
) (tous les éléments DOM seront disponibles au moment de l'exécution du script).D'autres solutions incluent l'écoute des événements
load
[MDN] ouDOMContentLoaded
[MDN] . Dans ces cas, peu importe où dans le document vous placez le code JavaScript, il vous suffit de vous rappeler de mettre tout le code de traitement DOM dans les gestionnaires d'événements.Exemple:
Veuillez consulter les articles sur quirksmode.org pour plus d'informations sur la gestion des événements et les différences de navigateur.
jQuery
Assurez-vous d'abord que jQuery est correctement chargé. Utilisez les outils de développement du navigateur pour savoir si le fichier jQuery a été trouvé et corrigez l'URL dans le cas contraire (par exemple, ajoutez le schéma
http:
ouhttps:
au début, ajustez le chemin, etc.)L'écoute des événements
load
/DOMContentLoaded
est exactement ce que jQuery fait avec.ready()
[docs] . Tout votre code jQuery qui affecte l'élément DOM doit se trouver dans ce gestionnaire d'événements.En fait, le didacticiel jQuery indique explicitement:
Alternativement, vous pouvez également utiliser la syntaxe abrégée:
Les deux sont équivalents.
la source
ready
événement pour refléter la syntaxe préférée "plus récente", ou est-il préférable de la laisser telle quelle pour qu'elle fonctionne avec les anciennes versions?$(window).load()
(et peut - être des solutions de rechange syntaxiques à la$(document).ready()
,$(function(){})
il semble lié, mais il? Sent un peu tangent au point que vous faites..load
. En ce qui concerne les alternatives de syntaxe, elles pourraient être consultées dans la documentation, mais comme les réponses devraient être autonomes, il pourrait être utile de les ajouter. Là encore, je suis presque sûr que ce bit spécifique sur jQuery a déjà été répondu et est probablement couvert dans une autre réponse et un lien vers celui-ci pourrait suffire..load
est obsolète: api.jquery.com/load-event . Je ne sais pas si c'est pour les images uniquement ouwindow
aussi.Raisons pour lesquelles les sélecteurs basés sur l'ID ne fonctionnent pas
Solutions
Essayez d'accéder à l'élément après sa déclaration ou utilisez des trucs comme
$(document).ready();
Pour les éléments provenant des réponses Ajax, utilisez la
.bind()
méthode de jQuery. Les anciennes versions de jQuery avaient.live()
la même chose.Utilisez des outils [par exemple, le plugin webdeveloper pour les navigateurs] pour trouver les identifiants en double et les supprimer.
la source
Comme l'a souligné @FelixKling, le scénario le plus probable est que les nœuds que vous recherchez n'existent pas (encore).
Cependant, les pratiques de développement modernes peuvent souvent manipuler des éléments de document en dehors de l'arborescence de documents soit avec DocumentFragments, soit simplement en détachant / rattachant directement les éléments actuels. Ces techniques peuvent être utilisées dans le cadre de modèles JavaScript ou pour éviter des opérations de repeinture / refusion excessives pendant que les éléments en question sont fortement modifiés.
De même, la nouvelle fonctionnalité "Shadow DOM" déployée sur les navigateurs modernes permet aux éléments de faire partie du document, mais pas d'interroger par document.getElementById et toutes ses méthodes apparentées (querySelector, etc.). Cette opération est effectuée pour encapsuler les fonctionnalités et les masquer spécifiquement.
Encore une fois, cependant, il est très probable que l'élément que vous recherchez ne figure tout simplement pas (encore) dans le document, et vous devriez faire comme le suggère Felix. Cependant, vous devez également savoir que ce n'est pas de plus en plus la seule raison pour laquelle un élément peut être introuvable (temporairement ou définitivement).
la source
Si l'élément auquel vous essayez d'accéder se trouve à l'intérieur d'un
iframe
et que vous essayez d'y accéder en dehors du contexte deiframe
cela, cela entraînera également son échec.Si vous souhaitez obtenir un élément dans un iframe, vous pouvez découvrir comment ici .
la source
Si l'ordre d'exécution du script n'est pas le problème, une autre cause possible du problème est que l'élément n'est pas sélectionné correctement:
getElementById
requiert que la chaîne passée soit l'ID mot pour mot , et rien d'autre. Si vous préfixez la chaîne passée avec un#
et que l'ID ne commence pas par un#
, rien ne sera sélectionné:De même, pour
getElementsByClassName
, ne préfixez pas la chaîne passée avec un.
:Avec querySelector, querySelectorAll et jQuery, pour faire correspondre un élément avec un nom de classe particulier, placez un
.
directement avant la classe. De même, pour faire correspondre un élément avec un ID particulier, mettez un#
directement avant l'ID:Les règles ici sont, dans la plupart des cas, identiques à celles des sélecteurs CSS, et peuvent être vues en détail ici .
Pour faire correspondre un élément qui a deux attributs ou plus (comme deux noms de classe, ou un nom de classe et un
data-
attribut), placez les sélecteurs pour chaque attribut côte à côte dans la chaîne de sélection, sans espace les séparant (car un espace indique le sélecteur descendant ). Par exemple, pour sélectionner:utilisez la chaîne de requête
.foo.bar
. Pour sélectionnerutilisez la chaîne de requête
.foo[data-bar="someData"]
. Pour sélectionner ce qui<span>
suit:utiliser
div.parent > span[data-username="bob"]
.La capitalisation et l'orthographe comptent pour tout ce qui précède. Si la capitalisation est différente, ou l'orthographe est différente, l'élément ne sera pas sélectionné:
Vous devez également vous assurer que les méthodes sont correctement capitalisées et orthographiées. Utilisez l'un des:
Toute autre orthographe ou capitalisation ne fonctionnera pas. Par exemple,
document.getElementByClassName
lancera une erreur.Assurez-vous de passer une chaîne à ces méthodes de sélection. Si vous passez quelque chose qui n'est pas une chaîne
querySelector
,getElementById
etc., presque certainement ne fonctionnera pas.la source
Quand j'ai essayé votre code, cela a fonctionné.
La seule raison pour laquelle votre événement ne fonctionne pas peut être que votre DOM n'était pas prêt et que votre bouton avec l'ID "event-btn" n'était pas encore prêt. Et votre javascript a été exécuté et a tenté de lier l'événement avec cet élément.
Avant d'utiliser l'élément DOM pour la liaison, cet élément doit être prêt. Il existe de nombreuses options pour ce faire.
Option 1: vous pouvez déplacer votre code de liaison d'événement dans un événement prêt pour le document. Comme:
Option 2: vous pouvez utiliser l'événement d'expiration, de sorte que la liaison soit retardée de quelques secondes. comme:
Option3: déplacez votre inclusion javascript au bas de votre page.
J'espère que ceci vous aide.
la source
le problème est que l'élément dom 'speclist' n'est pas créé au moment où le code javascript est exécuté. J'ai donc mis le code javascript dans une fonction et j'ai appelé cette fonction lors de l'événement onload du corps.
la source
Ma solution était de ne pas utiliser l'identifiant d'un élément d'ancrage:
<a id='star_wars'>Place to jump to</a>
. Apparemment, le blazor et les autres cadres de spa ont des problèmes pour sauter aux ancres sur la même page. Pour me déplacer, je devais utiliserdocument.getElementById('star_wars')
. Cependant , cela ne fonctionnait pas jusqu'à ce que je mets l'id dans un élément de paragraphe à la place:<p id='star_wars'>Some paragraph<p>
.Exemple utilisant bootstrap:
la source