Simple Fellow
Simple Fellow

Reputation: 4622

A confusion about JQuery design

I just started using the Jquery and I have the following understanding:

  1. Every selector of Jquery always returns a wrapped list of items which could be
    • An empty list
    • A list with single element
    • A list with many elements
  2. The chained function operates on the whole list not just one.

My confusion is:

A. How do some functions return the correct value even if they operate on a list with many elements for example data('something')?

B. If we specifically want to operate on a single item, what should we do?

Upvotes: 2

Views: 44

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074108

Every selector of Jquery always returns a wrapped list of items...

Not just when used with selectors, but yes, a jQuery object (the return value of $()) is a set of elements, with methods to act on the set.

(Rarely, a jQuery object contains things that aren't elements, such as the return value of map if you return non-elements from the callback, or if you use contents which includes text and comment nodes in addition to elements. But in the vast majority of cases, you're dealing with elements.)

A. How is it that even with that some functions return the correct value even if they operate on a list with many elements for example data('something')?

Very good question! The API is asymmetric. In most cases, when you use a function as a getter, it gets from the first element in the set; but when you use it as a setter, it sets on all elements in the set. Consider:

var a = $("a");
console.log(a.attr("href"));                // Shows the href attr of the
                                            //  **first** element
a.attr("href", "http://stackoverflow.com"); // Sets the href attr of **all**
                                            // elements in the set

The big exception to this rule is text, which returns the text of all elements in the set concatenated together, rather than just the text of the first element. Why? Er...ask John Resig. :-) It just is.

B. If we specifically want to operate on a single item, what should we do?

If you're just getting a value from the set, there's nothing special you need to do if the element is the first one; just use the getter (see above).

Otherwise, you have at least two options:

  1. Use first, last, eq, etc. to get a new jQuery set with just the element you want, or

  2. Use $(yourSet[n]) to build a new set around just the nth element

    jQuery objects are array-like; when you index into them with [] notation, you access the raw element at that index. So $(yourSet[n]) get the raw element (yourSet[n]) and then wraps it in a jQuery object.

Addressing your thoughts on it:

  • Iterate whole list treating like regular array

Sure; use each, which calls a callback function with this referring to each entry in the set. (It's also available as an argument.) Note that it will be the raw entry (e.g., the raw DOM element), not a jQuery object.

  • filter function of javascript?

jQuery has filter built in which (when you pass it a function) acts a lot like JavaScript's Array.prototype.filter. (Or you can pass it a string, and it will filter the set based on whether they match that string when used as a CSS selector.)

  • something else (could not figure out)

Another powerful aspect of jQuery's accessor functions is that most of them accept a callback, which lets you loop through the elements providing a different value to set for each of them (and you can return nothing if you want to leave the value unchanged for some of them). For instance, this appends the index of the element in the text to its text — but only for entries with odd-numbered indexes:

$("some-selector").text(function(index) {
    if (index % 2 === 1) {
        return $(this).text() + " - " + index;
    }
});

Examples of the various things above:

var divs = $("div.x");

// Getters get from the first entry in the set
console.log(divs.attr("class")); // "x a", the class of the first

// ...except for `text`, which is different:
console.log(divs.text()); // Text of all the elements joined together

// Setters set on all elements; this turns them all green:
divs.css("color", "green");

// Let's bold just the 3rd element:
divs.eq(2).css("font-weight", "bold");

// Let's make the 4th italic using [] notation:
$(divs[3]).css("font-style", "italic");

// Let's use `filter` to get just the elements with odd-numbered
// indexes, and use `each` on the result output their text
divs.filter(function(index) { return index % 2 === 1; }).each(function() {
    console.log($(this).text());
});

// Let's use `text` to add the index to the end of each element:
divs.text(function(index) {
    return $(this).text() + " - " + index;
});

// (Note: Using `css` above just to show how accessors work; in general
// prefer using classes to direct styling)
<div class="x a">first</div>
<div class="x b">second</div>
<div class="x c">third</div>
<div class="x d">fouth</div>
<div class="x e">fifth</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


In closing: In my view, the best way to get a thorough idea of all the ways you can use jQuery is to simply read through the API documentation from beginning to end. It only takes an hour, two at the most. Then do it again a month later. Then, when you come to do something, even though you may not remember exactly how you do it, you'll remember that you can do it, and know to find it again in the API.

Upvotes: 3

Related Questions