简体   繁体   中英

Parsing Returned Values of Class or Contains Selectors in jQuery

I have been researching this and trying just about every solution example that has been provided but cannot seem to process the returned values of jQuery $('a.someclass) or $('a:contains("some text")) in a meaningful way such as an array to be enumerated. The .length allows you to see how many items you got back and if you log to console the variable to which the above was assigned, you get a full dump of what was gathered but the most I can do is get information about the first item only.

Say I have an HTML such as this:

<a href="something" id="a1" class="a x">something.com</a>
<a href="anotherthing" id="a2" class="a x">anotherthing.com</a>

And I try to use jQuery in one of two ways to grab these:

//grabbing any link where class = 'a x'
var links = $("a.a.x");

or say:

//grabbing any link where the word "thing" appears
var links = $("a:contains('thing')");

I can inspect the returned information simply by:

console.log(links);
console.log(links.length);

However, there is no way I have found to parse the data beyond the first item as trying to treat it like an array links[i] provides an exception and using links by itself only gives you the attributes attached to the first item and not the subsequent ones.

For example, something like this won't work:

if (links.length > 0) {
   for (var i = 0; i < links.length; i++) {
       console.log(links[i].attr('href'));
   };
};

While simply doing this will work, but on the first item only:

console.log(links.attr('href'));

Can someone please enhance my understanding of what is going on here and how to enumerate and process code on all the items returned please. Thank you in advance.


EDIT : 08/07/15


I wanted to thank EVERYONE for their kind assist in this and taking the time to provide me examples that I shall use as a reference. Additionally wanted to report that I was able to get the functionality that I needed by incorporating nearly all of what was provided to me in some fashion to create a robust and lean code. Now if I can just get the darn .trigger('click') to function properly (or more accurately - consistently) then I will be absolutely golden.

It appears that the code using $("aax") has no trouble being triggered

if (links.length > 0){
    links.each(function(index, domElement) {
        console.log("["+index+"] "+domElement.href);
        $(domElement).trigger('click');
    });
};

but the same exact code applied to items from links gathered through $("a:contains('thing')") is not producing the desired behavior and provides no error. Truly a head scratcher. I need to resolve this somehow as I will not always have class or id available to me, leaving with contains as the only option. I would hate to grab ALL a tags on the page and then parse through them individually, it seems inefficient and certain inelegant.

The disconnect you are having is between the jQuery API and the native JavaScript API.

With jQuery, when you use a selector, internally it will mock an array. The array is essentially inside of the jQuery object. The internal array is the set of actual matched elements on the page, and those elements will have the native JavaScript API functions available to them. The entire jQuery object as a whole will have the jQuery API exposed to it.

Here is what that looks like in code, and how it applies to your examples.

Your links selector is just fine, "aax" . You have an anchor tag with both class "a" and class "x" and that is how you would select the set of tags matching those criteria. So you have

var links = $("a.a.x");

One thing to remember is that $ is just shorthand for jQuery which is a function. So you are calling that function and it is returning (through some internal process) an instance of jQuery. So links is now referencing the instance of jQuery. Internally, that instance (jQuery object) contains a variable with an array of the elements matched from the selector (argument) used with the jQuery call. This array can be accessed (as a result of jQuery's internal process exposing the elements) by simply using index numbers.

You are accessing the array properly (or at least without error) here:

for (var i = 0; i < links.length; i++) {
   console.log(links[i].attr('href'));
};

But there is an issue. Remember that the internal array of the jQuery object held the elements matched? links[i] here is the actual element, and is exposing the native JavaScript API. As a result, .attr is not available. The native version of the getter for attributes is "getAttribute", and you could change your above code to

for (var i = 0; i < links.length; i++) {
   console.log(links[i].getAttribute('href'));
};

You could also construct a jQuery object with links[i] and then access the jQuery API.

for (var i = 0; i < links.length; i++) {
   console.log($(links[i]).attr('href'));
};

Which begins to be redundant as you hopefully see. By similar construct, and because links is a jQuery object, you can access the jQuery API functions. That is why this code console.log(links.attr('href')); will result in the href attribute. However, as it is a getter, jQuery will internally only return the first result of the set. In order to use an iterative approach, jQuery exposes the function each . It is very useful and is used extensively behind the scenes. For example links.css('color','blue') will internally use each in order to iterate the entire set of links and change their text color to blue.

Your best best here would be to stick to using each .

$("a.a.x").each(function(){
    //this will now be available as the native element similar to links[i]
    console.log(this.href);//href is natively available as well
    cosnole.log(this.getAttribute('href'));//also available here
    console.log($(this).attr('href'));//and here when constructing a jQuery object as well
});

The way you write jQuery can be quite different from how you write normal JavaScript. It is quite seldom that you want to access single elements of your matches or explicitly loop through them. Most of the time you apply actions to all the matches at once in batch, as most jQuery functions applies to all matched elements in the list, for example:

$("a.a.x").addClass("link"); //Adds the class link to both elements.
$("a.a.x").css("color", "green"); //Makes both links green.

Did I mention you can chain these function calls?

$("a.a.x").addclass("link").css("color", "green"); //Same as above.

Sometimes you do need to loop over all the elements, though. Then you can use the each function:

//Set the width to be equal to the height of all divs with the class square.
$("div.square").each(function() {
    //This function is called once per matched element.
    //The variable "this" contains a DOM object referencing the current element.
    side = $(this).height();
    $(this).width(side);
}

If you just want to access a single element like you would from an array, you can use eq :

$("a.a.x").eq(1); //Gives you the second link.
$("a.a.x:eq(1)"); //Also available as selector.

Finally, if you want to access the underlying DOM object instead of the jQuery object you can either use get or brackets:

$("a.a.x").get(1); //Gives you the second link, as a DOM object
$("a.a.x")[1]; //Same as above.

Remember, jQuery is here to set you free from the tedious and boring parts of writing JavaScript. When you are used to do things the vanilla way you might produce code like this:

//BAD CODE - DO NOT IMMITATE.
links = $("a.a.x");
for(i=0; i<links.length; i++) {
    link = links.eq(i);
    link.addClass("link");
}

This is horrible code, since the same can be achieved in only one line - the very first one of all the examples of this answer.

Use .each iterator. For example:

var links = $("a.a.x");

links.each(function(index, domElement) {
console.log(index);
$(domElement).css('background', 'red');
});

btw - there are also .map, .filter, .eq, and lots of other methods to traverse the collection.

If your jQuery selector is correct, then you should be able to loop through the contents or use a .each() call

like

    var links = jQuery("a.a.x");
    links.each(function() {
        console.log(jQuery(this).attr('href'));
    });

Are you looking for something like this?

 var links = $("aax"); links.each(function(i) { console.log('item ' + i, links[i]); }); 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <a href="something" id="a1" class="ax">something.com</a> <a href="anotherthing" id="a2" class="ax">anotherthing.com</a> 

In the following code, a links[i] object is not a JQuery object but a DOM object so you should be able to access attribute as follows:

 var links = $("aax"); if (links.length > 0) { for (var i = 0; i < links.length; i++) { console.log(links[i].href); $('#list').append('<li> href='+links[i].href +'</li>'); }; }; 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script> <a href="something" id="a1" class="ax">something.com</a> <a href="anotherthing" id="a2" class="ax">anotherthing.com</a> <div> <ul id='list'> </ul> </div> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM