web-dev-qa-db-fra.com

Impossible de définir l'attribut de données à l'aide de l'API jQuery Data ()

J'ai le champ suivant sur une vue MVC:

@Html.TextBoxFor(model => model.Course.Title, new { data_helptext = "Old Text" })</span>

Dans un fichier js séparé, je souhaite définir l'attribut data-helptext sur une valeur de chaîne. Voici mon code:

alert($(targetField).data("helptext"));

$(targetField).data("helptext", "Testing 123");

L’appel alert() fonctionne correctement, il affiche le texte "Ancien texte" dans une boîte de dialogue d’alerte. Cependant, l'appel pour définir l'attribut data-helptext sur "Testing 123" ne fonctionne pas. "Old Text" est toujours la valeur actuelle de l'attribut.

Est-ce que j'utilise mal l'appel à data ()? J'ai regardé cela sur le Web et je ne vois pas ce que je fais mal.

Voici le balisage HTML:

<input data-helptext="Old Text" id="Course_Title" name="Course.Title" type="text" value="" />
131
Jason Evans

Il est mentionné dans la .data() documentation

Les attributs de données sont extraits lors du premier accès à la propriété de données, puis ne sont plus consultés ni mutés (toutes les valeurs de données sont ensuite stockées en interne dans jQuery).

Cela a également été couvert sur Pourquoi les modifications apportées à jQuery $ .fn.data () ne mettent-elles pas à jour les attributs HTML 5 data- * correspondants?

La démo de ma réponse originale ci-dessous ne semble plus fonctionner.

Réponse mise à jour

Encore une fois, à partir de la .data() documentation

Le traitement des attributs avec des tirets incorporés a été modifié dans jQuery 1.6 pour se conformer à la spécification HTML5 du W3C.

Donc pour <div data-role="page"></div> ce qui suit est vrai $('div').data('role') === 'page'

Je suis à peu près sûr que $('div').data('data-role') a fonctionné dans le passé, mais cela ne semble plus être le cas. J'ai créé une meilleure vitrine qui se connecte au HTML plutôt que d'avoir à ouvrir la console et a ajouté un exemple supplémentaire de conversion d'un trait d'union à la conversion de camelCase data-attributs .

Mise à jour de la démo (2015-07-25)

Voir aussi jQuery Data vs Attr?

HTML

<div id="changeMe" data-key="luke" data-another-key="vader"></div>
<a href="#" id="changeData"></a>
<table id="log">
    <tr><th>Setter</th><th>Getter</th><th>Result of calling getter</th><th>Notes</th></tr>
</table>

JavaScript (jQuery 1.6.2+)

var $changeMe = $('#changeMe');
var $log = $('#log');

var logger;
(logger = function(setter, getter, note) {
    note = note || '';
    eval('$changeMe' + setter);
    var result = eval('$changeMe' + getter);
    $log.append('<tr><td><code>' + setter + '</code></td><td><code>' + getter + '</code></td><td>' + result + '</td><td>' + note + '</td></tr>');
})('', ".data('key')", "Initial value");

$('#changeData').click(function() {
    // set data-key to new value
    logger(".data('key', 'leia')", ".data('key')", "expect leia on jQuery node object but DOM stays as luke");
    // try and set data-key via .attr and get via some methods
    logger(".attr('data-key', 'yoda')", ".data('key')", "expect leia (still) on jQuery object but DOM now yoda");
    logger("", ".attr('key')", "expect undefined (no attr <code>key</code>)");
    logger("", ".attr('data-key')", "expect yoda in DOM and on jQuery object");

    // bonus points
    logger('', ".data('data-key')", "expect undefined (cannot get via this method)");
    logger(".data('anotherKey')", ".data('anotherKey')", "jQuery 1.6+ get multi hyphen <code>data-another-key</code>");
    logger(".data('another-key')", ".data('another-key')", "jQuery < 1.6 get multi hyphen <code>data-another-key</code> (also supported in jQuery 1.6+)");

    return false;
});

$('#changeData').click();

Ancienne démo


Réponse originale

Pour ce HTML:

<div id="foo" data-helptext="bar"></div>
<a href="#" id="changeData">change data value</a>

et ce JavaScript (avec jQuery 1.6.2)

console.log($('#foo').data('helptext'));

$('#changeData').click(function() {
    $('#foo').data('helptext', 'Testing 123');
//  $('#foo').attr('data-helptext', 'Testing 123');
    console.log($('#foo').data('data-helptext'));
    return false;
});

Voir démo

En utilisant la console Chrome DevTools pour inspecter le DOM, la $('#foo').data('helptext', 'Testing 123'); ne fonctionne pas met à jour la valeur comme indiqué dans la console , mais $('#foo').attr('data-helptext', 'Testing 123'); le fait.

239
andyb

J'avais de sérieux problèmes avec

.data('property', value);

Il ne s'agissait pas de définir l'attribut data-property.

Commencé à utiliser .attr() :

Obtenez la valeur d'un attribut pour le premier élément de l'ensemble de éléments correspondants ou définir un ou plusieurs attributs pour chaque élément mis en correspondance élément.

.attr('property', value)

pour définir la valeur et

.attr('property')

pour récupérer la valeur.

Maintenant ça marche!

34
Leniel Maccaferri

La réponse acceptée de @ andyb a un petit bug. Suite à mon commentaire sur son post ci-dessus ...

Pour ce code HTML:

<div id="foo" data-helptext="bar"></div>
<a href="#" id="changeData">change data value</a>

Vous devez accéder à l'attribut comme ceci:

$('#foo').attr('data-helptext', 'Testing 123');

mais la méthode de données comme celle-ci:

$('#foo').data('helptext', 'Testing 123');

Le correctif ci-dessus pour la méthode .data () empêchera "undefined" et la valeur des données sera mise à jour (alors que le HTML ne le sera pas)

Le point de l'attribut "data" est de lier (ou "lier") une valeur à l'élément. Très similaire à l'attribut onclick="alert('do_something')", qui lie une action à l'élément ... le texte est inutile. Vous voulez simplement que l'action fonctionne lorsqu'elle clique sur l'élément.

Une fois que les données ou l'action sont liées à l'élément, généralement *, vous n'avez pas besoin de mettre à jour le code HTML, mais uniquement les données ou la méthode, car c'est ce que votre application (JavaScript) utiliserait. En ce qui concerne les performances, je ne vois pas pourquoi vous voudriez également mettre à jour le code HTML de toute façon, personne ne voit l’attribut html (sauf dans Firebug ou d’autres consoles).

Une façon d’y réfléchir: Le HTML (avec ses attributs) ne sont que du texte. Les données, fonctions, objets, etc. utilisés par JavaScript existent sur un plan séparé. Ce n'est que lorsque JavaScript est invité à le faire qu'il lit ou met à jour le texte HTML, mais toutes les données et fonctionnalités créées avec JavaScript agissent de manière totalement distincte du texte HTML/des attributs que vous voyez dans votre console Firebug (ou autre).

* Je mets l'accent sur généralement, car si vous devez conserver et exporter le code HTML (par exemple un éditeur de texte au format micro/données), le code HTML se chargera à nouveau sur une autre page. besoin du HTML mis à jour aussi.

8
Frank Forte

C'est arrivé pareil pour moi. Il se trouve que 

var data = $("#myObject").data();

vous donne un objet non-inscriptible. Je l'ai résolu en utilisant:

var data = $.extend({}, $("#myObject").data());

Et à partir de ce moment-là, data était un objet JS inscriptible standard.

6
Nico

Pour citer un devis:

Les attributs de données sont extraits la première fois que la propriété de données est accédé et ne sont plus accédés ou mutés (toutes les valeurs de données sont ensuite stockées en interne dans jQuery).

.data() - jQuery Documentiation

Notez que cette limitation (franchement odd) est uniquement réservée à l'utilisation de .data().

La solution? Utilisez .attr à la place.

Bien sûr, plusieurs d'entre vous peuvent se sentir mal à l'aise de ne pas utiliser cette méthode dédiée. Considérez le scénario suivant:

  • Le 'standard' est mis à jour afin que la partie données des attributs personnalisés ne soit plus requise/soit remplacée

Bon sens - Pourquoi changeraient-ils un attribut déjà établi comme ça? Imaginez simplement class begin renommé en group et id en identifier. Internet casserait.

Et même dans ce cas, javascript est capable de résoudre ce problème - et bien sûr, malgré son incompatibilité notoire avec HTML, REGEX (et diverses méthodes similaires) pourrait rapidement renommer vos attributs en ce nouveau "standard" mythique.

TL; DR

alert($(targetField).attr("data-helptext"));
3
Super Cat

Comme indiqué précédemment, la méthode .data() ne définit pas la valeur de l'attribut data- et ne lit pas les valeurs mises à jour si l'attribut data- est modifié.

Ma solution consistait à étendre jQuery avec une méthode.realData()qui correspond réellement à la valeur actuelle de l'attribut:

// Alternative to .data() that updates data- attributes, and reads their current value.
(function($){
  $.fn.realData = function(name,value) {
      if (value === undefined) {
        return $(this).attr('data-'+name);
      } else {
        $(this).attr('data-'+name,value);
      }
  };
})(jQuery);

NOTE: Bien sûr, vous pouvez simplement utiliser .attr(), mais d’après mon expérience, la plupart des développeurs (alias moi) commettent l’erreur de considérer .attr() et .data() comme interchangeables, et se substituent souvent les uns aux autres sans y penser. Cela peut fonctionner la plupart du temps, mais c'est un excellent moyen d'introduire des bogues, en particulier lorsqu'il s'agit de toute sorte de liaison de données dynamique. Donc, en utilisant .realData(), je peux être plus explicite sur le comportement souhaité.

1
Yarin

Avait le même problème. Comme vous pouvez toujours obtenir des données à l'aide de la méthode .data (), il vous suffit de trouver un moyen d'écrire sur les éléments. C'est la méthode d'assistance que j'utilise. Comme la plupart des gens l'ont dit, vous devrez utiliser .attr. Je le remplace à la place de _ comme je le sais. Je ne suis au courant d'aucun autre personnage qu'il remplace ... mais je n'ai pas fait de recherche à ce sujet. 

function ExtendElementData(element, object){
    //element is what you want to set data on
    //object is a hash/js-object
    var keys = Object.keys(object);
    for (var i = 0; i < keys.length; i++){
        var key = keys[i];
        $(element).attr('data-'+key.replace("_", "-"), object[key]);
    }
}

EDIT: 01/05/2017

J'ai constaté qu'il existait encore des cas où il était impossible d'obtenir les données correctes à l'aide de méthodes intégrées. Ce que j'utilise maintenant est la suivante:

function setDomData(element, object){
    //object is a hash

    var keys = Object.keys(object);
    for (var i = 0; i < keys.length; i++){
        var key = keys[i];
        $(element).attr('data-'+key.replace("_", "-"), object[key]);
    }
};

function getDomData(element, key){
    var domObject = $(element).get(0);
    var attKeys = Object.keys(domObject.attributes);

    var values = null;
    if (key != null){
        values = $(element).attr('data-' + key);
    } else {
        values = {};

        var keys = [];
        for (var i = 0; i < attKeys.length; i++) {
            keys.Push(domObject.attributes[attKeys[i]]);
        }

        for (var i = 0; i < keys.length; i++){
            if(!keys[i].match(/data-.*/)){
                values[keys[i]] = $(element).attr(keys[i]);
            }
        }
    }
    return values;
};
0
Matthew Pautzke