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";});