2

I'm doing some string manipulation to build a jquery selector. Does the trick, but seems a bit ugly to me. Is there a nicer way of doing what I'm doing below?

$(".hierarchical[data-dependson='"+id+"']")

Edit: why does it seem ugly? I'd like to avoid the string manipulation if I can. I've seen much nicer looking code using .eq and .has - but I can't see a way to use them here.

  • Just of note, for efficiency you should add the tag name to class selectors when possible. – John Hartsock Dec 08 '11 at 23:32
  • 1
    I think that looks perfectly nice. (And I can't think of a way to improve it) – Pekka Dec 08 '11 at 23:34
  • Why does it seem ugly to you? – Vigrond Dec 08 '11 at 23:36
  • 2
    @JohnHartsock - why does adding the tag name help? That would make extra work if the internal implementation was able to use `getElementsByClassName()` or `querySelectorAll()`. It seems it might only help if either of those methods didn't exist (e.g. very old browsers) and otherwise slow things down a small bit. – jfriend00 Dec 08 '11 at 23:38
  • IE8 (and lower) doesn't support `getElementsByClassName()` http://www.quirksmode.org/dom/w3c_core.html#t11 – canon Dec 08 '11 at 23:43
  • 1
    @antisanity - Why optimize your selectors for IE8 and below and make modern browsers slower? Seems backwards to me. Optimize for what most people use as long as older browser continue to work. I see no reason to add the tag type to most selectors unless you legitimately need the extra filtering by tag type. – jfriend00 Dec 09 '11 at 00:09
  • If it works, then it works, don't rely on code looks than functionality. – MacMac Dec 09 '11 at 00:10
  • @Vigrond I never said it looked ugly – John Hartsock Dec 09 '11 at 00:12
  • It seems like you are basically concerned because JQuery selector syntax _looks_ like an embedded DSL within JavaScript, but it _isn't_ so it doesn't support "magic" syntax like /regex/ does. JQuery accepts selectors as a complex structure flattened down and packed into a string. You don't seem to want to pack up a string to pass in, so you're looking for methods that accept the data in a "structured" form so you don't have to "tunnel" it through a string. I think .attrIs from Vigrond below is the best you're gonna get. – Mike Edwards Dec 09 '11 at 01:36
  • @John Harstock the OP said it was "ugly" in his original post – Mike Edwards Dec 09 '11 at 01:40
  • @Jfriend Do ou really consider IE 8 to be a very old browser? – John Hartsock Dec 09 '11 at 04:47
  • @jfriend00 Most people use modern browsers? Please cite any statistics which show that IE8 (and lower) is in the minority. – canon Dec 09 '11 at 04:52
  • @JohnHartsock - I NEVER said IE8 was a very old browser. I said it was silly to optimize for IE8 at the expense of the modern browsers (IE8 is not a modern browser). Depending upon who's statistics you believe, IE8 and older is 15-25% of the market. Modern browsers like Firefox 3.5+, Chrome, Safari and Opera are most of the rest of the market. I'd much rather optimize for the modern browsers and make sure it still works in the older browsers rather than the other way around. Optimize for 75-80% of the market rather than 20-25%. – jfriend00 Dec 09 '11 at 05:01
  • @JohnHartsock - a few browser statistic sources: [StatCounter](http://gs.statcounter.com/#browser_version-ww-monthly-201011-201111), [W3Counter](http://www.w3counter.com/globalstats.php), [Summary of various sites](http://www.upsdell.com/BrowserNews/stat.htm) – jfriend00 Dec 09 '11 at 05:18

4 Answers4

1

Searching by attributes other than class is slow, if you wanted to speed it up you could have that id be a class and select it like this:

$(".hierarchical."+id)

Here is a jsperf to show the difference in speed of the two types of selectors: http://jsperf.com/select-by-attribute-vs-class (Spoiler Alert: selecting by class is a couple times faster).

Jasper
  • 75,717
  • 14
  • 151
  • 146
1

How about this:

$.fn.attrIs = function(attr, value) { 
    return $(this).filter(function(index){
        return $(this).attr(attr) == value;
    });  
}

Then:

$(".hierarchical").attrIs("data-dependson", id);

Given a jQuery object collection, this attrIs(attr, value) function will reduce the collection to only those elements with attr == value

Here's an example: http://jsfiddle.net/RC652/

You could probably modify this method to better suit your own purpose.

Vigrond
  • 8,148
  • 4
  • 28
  • 46
  • 1
    `this` in that outer function is already a jQuery object, so no need to re-wrap it. Inside the inner function, you could also just `return $(this).attr(attr) == value;` – ehynds Dec 09 '11 at 16:12
  • i think the final answer is - "you can't avoid the string concat with vanilla jquery". but I like this helper method, will add it to my library and use it in the future – TesterTurnedDeveloper Dec 11 '11 at 23:58
0

What you are really missing is a nice formatting method for javascript so what you're trying to do isn't drowned out by all your quotes.

I like the format method referenced here. Here it is reproduced as a utility function so you don't have to monkey patch the built-in string object.

var format = function(target) {
  var args = arguments;
  return target.replace(/{(\d+)}/g, function(match, number) {
    number = parseInt(number) + 1;
    return typeof args[number] != 'undefined'
      ? args[number]
      : match
    ;
  });
};

Then you could do:

var selector = format(".hierarchical[data-dependson='{0}']", id);
// or with the monkey patch
selector = ".hierarchical[data-dependson='{0}']".format(id);
$(selector)

Still a little messy, but fundamentally you're splicing a value into a string. I also in no way vouch for the performance of any of this. Other answers probably make a good point that this is slow, but that's not your question.

Community
  • 1
  • 1
Mike Edwards
  • 3,742
  • 17
  • 23
0

You could filter it:

$(".hierarchical").filter(function(){
    return $(this).data("dependson") === id;
});
ehynds
  • 4,435
  • 3
  • 24
  • 23