33 votes

Pourquoi les modifications apportées à jQuery $.fn.data() ne mettent pas à jour les attributs data-* de html 5 correspondants ?

Voici un exemple simple pour illustrer le comportement :

Compte tenu de ce balisage html :

<div data-company="Microsoft"></div>

et ce code jQuery (utilisant jQuery 1.5.1) :

// read the data
alert($("div").data("company"));
// returns Microsoft <<< OK!

// set the data
$("div").data("company","Apple");
alert($("div").data("company"));
// returns Apple <<< OK!

// attribute selector
alert($("div[data-company='Apple']").length);
// returns 0  <<< WHY???

// attribute selector again
alert($("div[data-company='Microsoft']").length);
// returns 1  <<< WHY???

// set the attribute directly
$("div").attr("data-company","Apple");
alert($("div[data-company='Apple']").length);
// now returns 1 <<< OK!

Puisque jQuery importe automatiquement les data-* HTML5 dans l'objet data de jQuery, les attributs ne devraient-ils pas être mis à jour également lorsque les données changent ?

1 votes

@James "div[data-company='Apple'" - vous avez oublié de fermer avec ]

51voto

Dave Ward Points 36006

Normalement, il n'y a pas besoin d'aller-retour. .data() si vous utilisez systématiquement .data() pour accéder aux données des éléments du DOM, les définir ou les modifier. Pour cette raison, il est logique d'éviter la surcharge de performance que représente l'accès au DOM pour chaque élément .data() opération de définition/modification ( .data() stocke ses valeurs dans jQuery.cache en interne).

Si vous voulez forcer le comportement d'aller-retour vous-même, vous pouvez souscrire aux événements "setData" ou "changeData" et ensuite pousser le fichier .data() la mise à jour dans ces événements à travers l'élément DOM correspondant via .attr() .

2 votes

C'est logique - quelle serait alors la méthode préférée pour utiliser .data() dans le contexte d'un sélecteur ? Imaginons que je veuille accéder à tous les éléments où data-company='Microsoft' a été défini/modifié avec .data() ?

1 votes

Je ne pense pas qu'il y ait une méthode facile pour faire des requêtes sur les données de la .data() cache. Si vous voulez utiliser un tel sélecteur, vous devez implémenter le roundtripping sur l'événement "changeData" que j'ai mentionné. Ainsi, vous pourriez garder vos attributs de données en synchronisation avec .data() (et vous ne pourriez le faire que de manière sélective, sur les éléments que vous avez l'intention d'interroger plus tard).

0 votes

Merci, Dave ! Btw, j'ai apprécié votre série sur tekpub.

17voto

Craig Points 2715

C'est le comportement correct selon la documentation :

Les attributs data sont introduits lors du premier accès à la propriété data et ne sont ensuite plus accessibles ou modifiés (toutes les valeurs de données sont alors stockées en interne dans jQuery).

(de : http://api.jquery.com/data )

0 votes

Cela a-t-il toujours été le cas ou cela a-t-il été modifié dans l'une des versions ?

1 votes

Il semble que cela ait toujours été le cas. La citation de la documentation ci-dessus figure également dans les notes de mise à jour de la version 1.4.3, lorsque cette fonctionnalité a été lancée pour la première fois : blog.jquery.com/2010/10/16/jquery-143-released

0voto

oriadam Points 3663

Le sélecteur de requête de [data-company] vérifie les attributs, tandis que .data ne les met pas à jour.

Vous pouvez modifier le code pour utiliser uniquement .attr('data- éviter .data complètement.

Vous pouvez définir votre propre fonction qui met à jour à la fois data et attr :

// update both data and corresponding attribute 'data-x'
$.fn.attrdata = function (a, b)
{
    if (arguments.length > 1)
        this.attr('data-' + a, b);
    else if (typeof a === 'object')
        this.attr(Object.keys(a).reduce(function (obj, key)
        {
            obj['data-' + key] = a[key];
            return obj;
        }, {}));
    return this.data.apply(this, arguments);
};

Utilisez comme ça :

$("div").attrdata("company", "Apple");
$("div").attrdata({company: "Apple"}); // also possible
console.log($("div").data("company")); // Apple
console.log($("div").attr("data-company")); // Apple
console.log($("div[data-company='Apple']").length); // 1

Si vous n'utilisez pas les sélecteurs CSS, vous pouvez créer votre propre sélecteur jQuery :

$.expr[':'].data = function(elem, index, match) {
  var split = match[3].split('=');
  return $(elem).data(split[0]) == split[1];
};

Utilisez comme ça :

$("div").attr("data-company", "Microsoft");
$("div").data("company", "Apple");
console.log($('div:data(company=Apple)').length); // 1
console.log($('div[data-company="Apple"]').length); // 0

https://jsfiddle.net/oriadam/a14jvqcw/

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