128 votes

jQuery .data() ne fonctionne pas, mais .attr() fonctionne

Pardonnez-moi de ne pas avoir été plus précis. J'ai un bug très étrange. Après le chargement de la documentation, je boucle certains éléments qui ont à l'origine data-itemname="" et j'ai fixé ces valeurs à l'aide de .attr("data-itemname", "someValue") .

Question : Lorsque je passe ensuite en boucle sur ces éléments, si je fais elem.data().itemname J'obtiens "" mais si je le fais elem.attr("data-itemname") J'obtiens "someValue" . C'est comme la fonction .data() n'obtient que les éléments qui sont initialement définis pour contenir une valeur, mais s'ils sont vides à l'origine, puis définis par la suite, alors .data() ne reçoit pas la valeur plus tard.

J'ai essayé de recréer ce bogue mais je n'y suis pas parvenu.

Editer

J'ai recréé le bug ! http://jsbin.com/ihuhep/edit#javascript,html,live

Aussi, des extraits du lien ci-dessus...

JS :

var theaters = [
    { name: "theater A", theaterId: 5 },
    { name: "theater B", theaterId: 17 }
];

$("#theaters").html(
    $("#theaterTmpl").render(theaters)
);

// DOES NOT WORK - .data("name", "val") does NOT set the val
var theaterA = $("[data-theaterid='5']");
theaterA.find(".someLink").data("tofilllater", "theater5link"); // this does NOT set data-tofilllater
$(".someLink[data-tofilllater='theater5link']").html("changed link text"); // never gets changed

// WORKS - .attr("data-name", "val") DOES set val
var theaterB = $("[data-theaterid='17']");
theaterB.find(".someLink").attr("data-tofilllater", "theater17link"); // this does set data-tofilllater
$(".someLink[data-tofilllater='theater17link']").html("changed link text");

HTML :

<body>
    <div id="theaters"></div>
</body>

<script id="theaterTmpl" type="text/x-jquery-tmpl">
    <div class="theater" data-theaterid="{{=theaterId}}">
        <h2>{{=name}}</h2>
        <a href="#" class="someLink" data-tofilllater="">need to change this text</a>
    </div>
</script>

240voto

leepowers Points 16420

J'ai rencontré un "bug" similaire il y a quelques jours alors que je travaillais avec .data() et .attr('data-name') pour les attributs de données HTML5.

Le comportement que vous décrivez n'est pas un bogue, mais a été conçu.

En .data() est spécial - non seulement il récupère les attributs de données HTML5, mais il tente également d'évaluer/parser les attributs. Ainsi, avec un attribut comme data-myjson='{"hello":"world"}' lorsqu'il est récupéré par l'intermédiaire de .data() renverra un Object tandis que l'extraction par .attr() renvoie une chaîne de caractères. Voir l'exemple de jsfiddle.

Depuis .data() effectue un traitement supplémentaire, jQuery stocke les résultats de l'évaluation de l'attribut dans le fichier $.cache - après tout, une fois qu'un attribut de données a été évalué, il serait inutile de le réévaluer à chaque fois. .data() d'autant plus que les variables de données peuvent contenir des chaînes JSON complexes.

Si j'ai dit tout cela, c'est pour dire la chose suivante : Après avoir récupéré un attribut via .data() toute modification apportée par .attr('data-myvar', '') n'est pas vu par les autres .data() appels. Testez-le sur jsfiddle.

Pour éviter ce problème ne pas mélanger .data et .attr() appels. Utilisez l'un ou l'autre.

26voto

T.J. Crowder Points 285826

C'est le résultat d'un malentendu : *data n'est PAS un accesseur pour `data-` attributs** . C'est à la fois plus et moins que cela.

data est un accesseur pour le cache de données de jQuery sur l'élément. Ce cache est initialisé de data-* s'il y en a, mais data jamais écrit aux attributs, et le changement d'attribut ne modifie pas non plus le cache de données après l'initialisation :

const div = $("[data-example]");
console.log('div.data("example"):', div.data("example"));
console.log('div.attr("data-example"):', div.attr("data-example"));
console.log('Using div.data("example", "updated")');
div.data("example", "updated");
console.log('div.data("example"):', div.data("example"));
console.log('div.attr("data-example"):', div.attr("data-example"));

<div data-example="initial value"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

data Il manipule également ce qu'il trouve de diverses manières, en devinant les types de données, en faisant des data("answer") sur un élément avec data-answer="42" un nombre, pas une chaîne, ou même analyser les choses comme du JSON si elles ressemblent à du JSON :

console.log(typeof $("[data-answer]").data("answer"));
console.log(typeof $("[data-json]").data("json"));
console.log(typeof $("[data-str]").data("str"));

<div data-answer="42"></div>
<div data-json='{"answer":42}'></div>
<div data-str="example"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Si vous souhaitez utiliser les attributs (à la fois pour les lire et les définir), utilisez attr no data . attr est un accesseur pour les attributs.

23voto

Elmar Höfinghoff Points 132

.attr("data-itemname", "someValue") modifie le DOM.

.data("itemname", "someValue") modifie le cache jQuery.

Pour que cela fonctionne dans le Javascript suivant et en plus dans le CSS, vous devez définir les deux.

theaterA.find(".someLink").attr("data-itemname", "someValue");
theaterA.find(".someLink").data("itemname", "someValue");

6voto

Marc B Points 195501

C'est parce que le nom de l'attribut est data-itemname . Vous ne pouvez pas utiliser - en abrégé obj.attribute (obj.data-itemname serait interprété comme "obj.data moins itemname").

4voto

Nico Points 13021

Pourquoi ne pas utiliser .data() partout ?

Vous pouvez également déclarer des valeurs par défaut en ligne dans le code HTML, ce qui est également très bien.

<span data-code="pony">text</span>

et

$("span").data("code") == "pony" // true

si vous souhaitez le modifier, il vous suffit de le faire

$("span").data("code", "not-a-pony");

et pour le supprimer complètement, vous pouvez invoquer

$("span").removeData("code");

vous devriez vraiment essayer d'éviter d'utiliser .attr("data-*") Je ne vois pas pourquoi vous voudriez le faire de toute façon.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X