jquery data selector jquery data selector jquery jquery

jquery data selector


At the moment I'm selecting like this:

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

Which seems to work just fine, but it would be nice if jQuery was able to select by that attribute without the 'data-' prefix.

I haven't tested this with data added to elements via jQuery dynamically, so that could be the downfall of this method.


I've created a new data selector that should enable you to do nested querying and AND conditions. Usage:

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

The pattern is:

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

"operator" and "check" are optional. So, if you only have :data(a.b.c) it will simply check for the truthiness of a.b.c.

You can see the available operators in the code below. Amongst them is ~= which allows regex testing:

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

I've tested it with a few variations and it seems to work quite well. I'll probably add this as a Github repo soon (with a full test suite), so keep a look out!

The 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;    };}());


You can also use a simple filtering function without any plugins. This is not exactly what you want but the result is the same:

$('a').data("user", {name: {first:"Tom",last:"Smith"},username: "tomsmith"});$('a').filter(function() {    return $(this).data('user') && $(this).data('user').name.first === "Tom";});