31

I guess this will be voted down, as it doesn't contain enough jQuery, but here it goes :)

What is the most effective way to get the element(s) returned by the jQuery selector below using plain old javascript?

$('a[title="some title text here"]', top.document)
markus
  • 40,136
  • 23
  • 97
  • 142
Jørgen
  • 8,820
  • 9
  • 47
  • 67
  • 1
    Can we ask why you would want to do this? – griegs Sep 01 '11 at 06:15
  • 2
    JS is no older than jQuery. jQuery is pure JS, so how can JS be old? – markus Sep 01 '11 at 06:24
  • @griegs I need to add some custom validation to a proprietary CMS. – Jørgen Sep 01 '11 at 06:33
  • 2
    @markus: JS _is_ older than jQuery, unless you're suggesting the jQuery library was released at the same time as JavaScript? Haven't you ever heard the expression "plain old something"? (Plain old common sense?) – nnnnnn Sep 01 '11 at 06:36
  • 1
    @jorgen "I guess this will be voted down, as it doesn't contain enough jQuery" I think you misunderstand the voting - it's not a like/dislike button. Your question is valid, clear, and answerable. If anything, it should receive up votes. – Bernhard Hofmann Sep 01 '11 at 06:39
  • @Bernhard Hofmann Thanks :) Actually it was an ironic statement based on all the "not enough jquery"-comments you'll find to answers providing alternative solutions to jquery. – Jørgen Sep 01 '11 at 06:43
  • 1
    @nnnnnn What I mean is that jQuery is fully contained in JS, it's just a library written in JS. Every bit of code is as old as JS because it IS JS. Why I wrote this is to counter the often read believe that using a library is better than writing your own. Which is often the case but just as often it isn't. – markus Sep 01 '11 at 06:53
  • 4
    @markus - I guessed what you meant, but it's not what you said. I agree with you about use of libraries not always being the best option, and I agree that we should counter the erroneous idea some people have that jQuery is a special extension to the language that does things that can't be done in "plain" JavaScript. But to say that all the [jQuery] code is as old as JS because it is written in JS is like saying that a poem I wrote this morning is as old as the alphabet. – nnnnnn Sep 01 '11 at 07:18
  • @markus—so if I write something in C I can say "it's as old as C"? Yes, jQuery itself is plain **old** javascript. Javascript was released in [1995](http://en.wikipedia.org/wiki/JavaScript#History), jQuery in [2006](http://en.wikipedia.org/wiki/Jquery). – RobG Sep 01 '11 at 07:28
  • 2
    This is a relevant question. There are situations where it is undesirable to require the jQuery library to be included in a web site. – Gruber Nov 19 '12 at 10:46

3 Answers3

32

If you're using a modern browser, you could use this:

window.top.document.querySelectorAll('a[title="some title text here"]')
icktoofay
  • 126,289
  • 21
  • 250
  • 231
14

Not sure if it’s the most effective, but at least it works.

var links = top.document.getElementsByTagName('a');
var result = [];
var linkcount = links.length;
for ( var i = 0; i < linkcount; i++) {
    if (links[i].getAttribute('title') === 'some title text here') {
        result.push(links[i]);
    }
}
margusholland
  • 3,306
  • 1
  • 23
  • 30
  • Depends, whether you want to get all A tags that have the title tag set or you want to get all elements that have a specific tag. Now that I look at the question again, you are correct. – margusholland Sep 01 '11 at 06:29
  • I'm not seeing enough === and !== people. ;) – Bernhard Hofmann Sep 01 '11 at 06:31
  • and yes it should be "===" :) – naveen Sep 01 '11 at 06:35
  • @margusholland You must change _links[i].title=='some...'_ to _links[i].getAttibute('title')==='some...'_. It's because if title (or any other) attribute is not set _links[i].getAttibute('title')_ returns _null_, but _links[i].title_ returns zero-length string. And usage of getAttribute() is more complex solution (custom attributes) – Andrew D. Sep 01 '11 at 06:44
  • For a performance gain, doing `var linksLength = links.length; for (var i = 0; i < linksLength; i++)` is a lot better :) No need to recalculate the length at every loop. – Florian Margaine Sep 01 '11 at 06:54
  • Note that A elements are used for links and anchors, and can be both at once. See the [HTMLAnchorElement](http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-48250443) and [HTMLLinkElement](http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-35143001)interfaces. There is also a [links](http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-7068919) and [anchors](http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-7577272) collections so no need for *getElementsByTagName*. – RobG Sep 01 '11 at 07:12
  • @Andrew—there is no need for *getAttribute*. Direct access to the *title* property is much faster than a call to *getAttribute* and if not set, does not cause **any** issues in the answer, whereas *getAttribute* is known to be buggy in some browsers. – RobG Sep 01 '11 at 07:29
  • @RobG, actually it does, because if you check for elements that have an empty title, you get wrong results. And the links and anchors might not help of you want all A tags and not just one or the other. – margusholland Sep 01 '11 at 07:31
  • @margusholland—how? Comparing any non-empty string to '' or *null* will give false. Besides, in all vesions of IE less tha 9 *getAttribute* will return an empty string for not set attributes anyway. – RobG Sep 01 '11 at 07:33
  • @RobG: Try: __1)__ _node.removeAttribute('title');node.title==="";_ (return true, but must return false) __2)__ _node.setAttribute('title','');node.title==="";_ (return true - is right). _node.getAttribute('title')===""_ in both cases returns right result. Checked in Chrome. I'm known about speed difference, but this more proper way for using as 'selectors' based on attributes. – Andrew D. Sep 01 '11 at 07:36
  • @Andrew - you are using the wrong test. The OP wants to compare a **non empty** string to the current value of the title. A **non empty** string will never be equal to an empty string or *null*. And *null* is never `===` to anything other than *null*. Trying to distinguish between an absent *title* attribute and one that has been set to empty string will fail in IE < 9 anyway, even using set/getAttribute – RobG Sep 02 '11 at 02:55
  • @RobG - What means the selector '_tagName[attributeName=""]_'. It select all elements with tag named tagName and attribute (not an property) named attributeName, where attribute attributeName is exist (defined) and it's value equals to "" (empty string). 1) You cannot use _property_ because it's not defined for curstom attributes. 2) For crossbrowsing, full check for above selector is: **node.tagName==="tagName" && node.hasAttribute("attributeName") && node.getAttribute("tagName")==="_(empty string)_"** – Andrew D. Sep 02 '11 at 05:22
  • @Andrew - you are enthusiastic. :-) It's rare to want to select by an empty attribute rather than a missing attribute, and extremely difficult since before version 9, IE incorrectly implemented *getAttribute* so that it was impossible to distinguish between the two using it. And you keep not reading the OP: `a[title="some title text here"]`. For the vast majority of cases, the requirement is to treat empty and non-existant *title* attributes the same (and HTML5 reflects that). – RobG Sep 04 '11 at 00:03
3

Here is an example

var getElements = function(tagName, attribute, value, callback) {
  var tags = window.document.getElementsByTagName(tagName);
  for (var i=0; i < tags.length; i++) {
    var tag = tags[i];
    if (tag.getAttribute(attribute) == value) {
      callback(tag);
    }
  };
};

getElements("a", "title", "PHP power player at Hettema & Bergsten. Click to learn more.", function(tag) {
  console.log(tag);
});
James Kyburz
  • 13,775
  • 1
  • 32
  • 33