web-dev-qa-db-fra.com

jquery data selector

Je dois sélectionner des éléments en fonction des valeurs stockées dans l'objet .data() d'un élément. Au minimum, j'aimerais sélectionner les propriétés de données de niveau supérieur à l'aide de sélecteurs, comme suit:

$('a').data("category","music");
$('a:data(category=music)');

Ou peut-être que le sélecteur serait dans un format de sélecteur d'attribut normal:

$('a[category=music]');

Ou au format attribut, mais avec un spécificateur pour indiquer qu'il est dans .data():

$('a[:category=music]');

J'ai trouvé que implémentation de James Padolsey était simple, mais bon. Les formats de sélecteur ci-dessus reflètent les méthodes montrées sur cette page. Il y a aussi ceci patch Sizzle .

Pour une raison quelconque, je me souviens de lire il y a quelque temps que jQuery 1.4 incluait la prise en charge des sélecteurs sur les valeurs de l'objet jquery .data(). Cependant, maintenant que je le cherche, je ne le trouve pas. Peut-être que c'était juste une demande de fonctionnalité que j'ai vue. Y at-il un soutien pour cela et je ne le vois tout simplement pas?

Idéalement, j'aimerais prendre en charge les sous-propriétés dans data () en utilisant la notation par points. Comme ça:

$('a').data("user",{name: {first:"Tom",last:"Smith"},username: "tomsmith"});
$('a[:user.name.first=Tom]');

Je souhaite également prendre en charge plusieurs sélecteurs de données, où seuls les éléments avec TOUS les sélecteurs de données spécifiés sont trouvés. Le sélecteur multiple de jquery normal effectue une opération OR. Par exemple, $('a.big, a.small') sélectionne a balises de classe big ou small). Je cherche un AND, peut-être comme ça:

$('a').data("artist",{id: 3281, name: "Madonna"});
$('a').data("category","music");
$('a[:category=music && :artist.name=Madonna]');

Enfin, il serait bon que les opérateurs de comparaison et les fonctionnalités de regex soient disponibles sur les sélecteurs de données. Donc, $(a[:artist.id>5000]) serait possible. Je me rends compte que je pourrais probablement en faire beaucoup avec filter(), mais il serait bien d’avoir un format de sélecteur simple.

Quelles solutions sont disponibles pour le faire? Jame's Padolsey est-il la meilleure solution en ce moment? Ma préoccupation concerne principalement les performances, mais également les fonctionnalités supplémentaires telles que la notation par points des sous-propriétés et les sélecteurs de données multiples. Y a-t-il d'autres implémentations qui prennent en charge ces choses ou sont meilleures d'une manière ou d'une autre?

183
Tauren

J'ai créé un nouveau sélecteur data qui devrait vous permettre d'effectuer des requêtes imbriquées et des conditions AND. Usage:

$('a:data(category==music,artist.name==Madonna)');

Le motif est:

:data( {namespace} [{operator} {check}]  )

"operator" et "check" sont optionnels. Donc, si vous avez seulement :data(a.b.c), il recherchera simplement le vérité de a.b.c.

Vous pouvez voir les opérateurs disponibles dans le code ci-dessous. Parmi eux figure ~= qui permet de tester les expressions rationnelles:

$('a:data(category~=^mus..$,artist.name~=^M.+a$)');

Je l'ai testé avec quelques variantes et il semble fonctionner assez bien. J'ajouterai probablement ceci bientôt sous forme de rapport Github (avec une suite de tests complète), alors surveillez-le!

Le code:

(function(){

    var matcher = /\s*(?:((?:(?:\\\.|[^.,])+\.?)+)\s*([!~><=]=|[><])\s*("|')?((?:\\\3|.)*?)\3|(.+?))\s*(?:,|$)/g;

    function resolve(element, data) {

        data = data.match(/(?:\\\.|[^.])+(?=\.|$)/g);

        var cur = jQuery.data(element)[data.shift()];

        while (cur && data[0]) {
            cur = cur[data.shift()];
        }

        return cur || undefined;

    }

    jQuery.expr[':'].data = function(el, i, match) {

        matcher.lastIndex = 0;

        var expr = match[3],
            m,
            check, val,
            allMatch = null,
            foundMatch = false;

        while (m = matcher.exec(expr)) {

            check = m[4];
            val = resolve(el, m[1] || m[5]);

            switch (m[2]) {
                case '==': foundMatch = val == check; break;
                case '!=': foundMatch = val != check; break;
                case '<=': foundMatch = val <= check; break;
                case '>=': foundMatch = val >= check; break;
                case '~=': foundMatch = RegExp(check).test(val); break;
                case '>': foundMatch = val > check; break;
                case '<': foundMatch = val < check; break;
                default: if (m[5]) foundMatch = !!val;
            }

            allMatch = allMatch === null ? foundMatch : allMatch && foundMatch;

        }

        return allMatch;

    };

}());
102
James

Pour le moment, je sélectionne comme ceci:

$('a[data-attribute=true]')

Ce qui semble bien fonctionner, mais ce serait bien si jQuery était capable de sélectionner cet attribut sans le préfixe 'data-'.

Je n'ai pas testé cela avec les données ajoutées aux éléments via jQuery de manière dynamique, de sorte que cela pourrait être la chute de cette méthode.

175
Ash

Vous pouvez également utiliser une fonction de filtrage simple sans plug-ins. Ce n'est pas exactement ce que vous voulez, mais le résultat est le même:

$('a').data("user", {name: {first:"Tom",last:"Smith"},username: "tomsmith"});

$('a').filter(function() {
    return $(this).data('user') && $(this).data('user').name.first === "Tom";
});
83
Dmitri

Je tiens à vous avertir que $('a[data-attribute=true]') ne fonctionne pas, selon la réponse d'Ashley, si vous attachez des données à un élément DOM via la fonction data ().

Cela fonctionne comme prévu si vous ajoutiez un attr de données dans votre code HTML, mais jQuery stocke les données en mémoire afin que les résultats obtenus avec $('a[data-attribute=true]') ne soient pas corrects.

Vous devez utiliser le plug-in de données http://code.google.com/p/jquerypluginsblog/ , utiliser la solution de Dmitri filter ou effectuer un $ .each sur tous les éléments. et vérifiez itérativement .data ()

24
Clarence Liu

Il y a un :data() filter plugin qui ne fait que ça :)

Quelques exemples basés sur votre question:

$('a:data("category=music")')
$('a:data("user.name.first=Tom")');
$('a:data("category=music"):data("artist.name=Madonna")');
//jQuery supports multiple of any selector to restrict further, 
//just chain with no space in-between for this effect

La performance ne sera pas très bonne comparée à ce qui est possible , choisir parmi $._cache et saisir les éléments correspondants est de loin le plus rapide. , mais beaucoup plus rond et pas très "jQuery-ey" en termes de comment arriver à des choses (vous venez généralement du côté élément). Bien sûr, je ne suis pas sûr que ce soit le plus rapide, car passer d’un identifiant unique à un élément est compliqué en soi, en termes de performances.

Le sélecteur de comparaison que vous avez mentionné sera préférable dans .filter() , il n’ya pas de support intégré pour cela dans le plugin, bien que vous puissiez l’ajouter sans trop de problèmes.

11
Nick Craver

Vous pouvez définir un attribut data-* sur un orme à l'aide de attr(), puis sélectionner à l'aide de cet attribut:

var Elm = $('a').attr('data-test',123); //assign 123 using attr()
Elm = $("a[data-test=123]"); //select Elm using attribute

et maintenant pour cet Elm, attr() et data() donneront 123 :

console.log(Elm.attr('data-test')); //123
console.log(Elm.data('test')); //123

Toutefois, si vous modifiez la valeur pour qu'elle soit 456 à l'aide de attr(), data() sera toujours 123 :

Elm.attr('data-test',456); //modify to 456
Elm = $("a[data-test=456]"); //reselect Elm using new 456 attribute

console.log(Elm.attr('data-test')); //456
console.log(Elm.data('test')); //123

Donc, si j'ai bien compris, vous devriez probablement éviter de mêler les commandes attr() et data() dans votre code si vous n'y êtes pas obligé. Parce que attr() semble correspondre directement au DOM alors que data() interagit avec la 'mémoire', bien que sa valeur initiale puisse être celle du DOM. Mais le point clé est que les deux ne sont pas nécessairement du tout synchronisés.

Alors soyez prudent.

Quoi qu'il en soit, si vous ne modifiez pas l'attribut data-* dans le DOM ou dans la mémoire, vous n'aurez pas de problème. Dès que vous commencez à modifier les valeurs, des problèmes potentiels peuvent survenir.

Merci à @Clarence Liu pour la réponse de @ Ash, ainsi que ce post .

7
D.Tate
$('a[data-category="music"]')

Ça marche. Voir sélecteur d'attributs égaux [nom = "valeur"]) .

6
Jorge Orpinel

Si vous utilisez également jQueryUI, vous obtenez une version (simple) du sélecteur :data qui vérifie la présence d'un élément de données, ce qui vous permet d'effectuer quelque chose comme $("div:data(view)") ou $( this ).closest(":data(view)").

Voir http://api.jqueryui.com/data-selector/ . Je ne sais pas depuis combien de temps ils en ont, mais c'est là maintenant!

5
Paul

Voici un plugin qui simplifie la vie https://github.com/rootical/jQueryDataSelector

Utilisez-le comme ça:

data selector           jQuery selector
  $$('name')              $('[data-name]')
  $$('name', 10)          $('[data-name=10]')
  $$('name', false)       $('[data-name=false]')
  $$('name', null)        $('[data-name]')
  $$('name', {})          Syntax error
3
Rootical V.