Iteration of Arrays and Objects - The jQuery API - Web Development with jQuery (2015)

Web Development with jQuery (2015)

Part I. The jQuery API

Chapter 5. Iteration of Arrays and Objects

This chapter discusses the methods jQuery provides to help you work with looking at the contents of arrays and objects. Historically, working with arrays or objects in JavaScript often required you to come up with your own helper methods and to deal with writing tedious redundant code every time you wanted to enumerate over the contents of an array—for example, creating a counter variable each time you wanted to enumerate over the content of an array.

As you saw in Chapter 4, “Manipulating Content and Attributes,” jQuery provides a rich, robust, and helpful API for various tasks associated with manipulating the content in a document. In this chapter, you see that jQuery also does not leave much to be desired in what it offers for dealing with arrays or objects.

Enumerating Arrays

In this section, you learn how to approach the task of enumerating or iterating over an array of values using jQuery's $.each() method, by calling each() via jQuery and each() directly. The term enumerate means to examine items one by one, and the term iteratemeans to do something repeatedly. These terms are often used interchangeably to describe the process of looking at the contents of an array, list, or object. Up to now, when looking at each individual value contained within an array, you might be used to dealing with a loop that looks something like this, which is the way it was been done in JavaScript before frameworks such as jQuery became ubiquitous:

var divs = document.getElementsByTagName('div');

for (var counter = 0; counter < divs.length; counter++)

{

// Do something with each item

console.log(divs[counter].innerHTML);

}

You have an array of items, a static node list, a live node list, or possibly an object. (By the way, in JavaScript, all arrays are objects, but not all objects are arrays.) Then you make a for loop, define a counter, and proceed to iterate over the contents of your array or list. If instead you want to iterate over an object, you'd instead use a for/in construct to look at the properties of the object.

jQuery makes creating a for construct unnecessary by providing a way to iterate over an array or list using a function call instead of a for loop and a callback function that's called for each individual item present in the array or object. Inside that callback function, you can do something with each individual item contained in the array, object, or list.

jQuery provides multiple functions for enumeration, which are covered in this chapter. The function that jQuery provides for basic enumeration is called each(), and it is demonstrated via two possible ways of application, in the following example, Example 5-1:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>The Beatles Discography</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-1.js'></script>

<link href='Example 5-1.css' rel='stylesheet' />

</head>

<body>

<h4>The Beatles</h4>

<ul id='beatles'>

</ul>

<h4>Discography</h4>

<ul id='beatlesAlbums'>

</ul>

</body>

</html>

The preceding markup document is linked to the following style sheet:

body {

font: 12px "Lucida Grande", Arial, sans-serif;

color: rgb(50, 50, 50);

margin: 0;

padding: 0 10px;

}

body ul {

list-style: none;

margin: 0 0 10px 0;

padding: 10px;

background: yellow;

width: 250px;

}

h4 {

margin: 10px 0;

}

The following script demonstrates jQuery's each() method called both via jQuery and directly.

$(document).ready(

function()

{

var beatles = [

'John Lennon',

'Paul McCartney',

'George Harrison',

'Ringo Starr'

];

var ul = $('ul#beatles');

// each() called via jQuery

$(beatles).each(

function()

{

ul.append('<li>' + this + '</li>');

}

);

var albums = [

'Please Please Me',

'With the Beatles',

'A Hard Day\'s Night',

'Beatles for Sale',

'Help!',

'Rubber Soul',

'Revolver',

'Sgt. Pepper\'s Lonely Hearts Club Band',

'Magical Mystery Tour',

'The Beatles',

'Yellow Submarine',

'Abbey Road',

'Let It Be'

];

ul = $('ul#beatlesAlbums');

// each() called directly.

$.each(

albums,

function()

{

ul.append('<li>' + this + '</li>');

}

);

}

);

In the preceding script, you create a couple of arrays, one for beatles and one for albums. In the first iteration, the variable beatles is passed to jQuery's dollar sign method, and then jQuery's each() method is chained onto that. You pass a callback function to jQuery'seach() method, which is executed once for each item in the array; upon each execution, the current item is passed to the callback function; the value is assigned to this. You can also define arguments within the callback function to get the current key (a numeric offset in the case of an array or list) or the current value, like so:

$(beatles).each(

function(key, value)

{

ul.append('<li>' + value + '</li>');

}

);

For these two arrays, the numeric offset is provided in key, the first argument, and the value is provided in the second argument, value. The same value is assigned to the special contextual keyword: this, which is available only within the callback function itself.

Figure 5.1 shows that both <ul> elements are populated with new <li> elements via script.

image

Figure 5.1

In the preceding example, you see how jQuery can eliminate the traditional for construct that you'd typically use for iterating the contents of an array or list. Instead, you pass an array to jQuery's dollar sign method so that you have the full power of jQuery at your disposal for use with that array. Then you chain a call to jQuery using the each() method, which takes a callback function as its only argument. That callback function then is executed once for each item in the array, eliminating the need for a counter because the current item is passed to the function with each iteration in the this keyword. The current index and value can be accessed optionally by providing two arguments to the callback function. Alternatively, you can also call each() directly. Calling each() directly places the array as the first argument and the callback function as the second argument.

Unfortunately, enumerating objects isn't as flexible as enumerating arrays, which is covered in the next section.

Enumerating Objects

Enumerating objects with jQuery is done by calling each() directly; when each() is called via jQuery, jQuery gets confused about what it is supposed to do with the object because jQuery does other things with objects passed to it this way. The following script takes another look at the example presented in Example 5-1, but this time both of the arrays are rewritten as plain objects, so you can observe the differences between enumerating an array and enumerating an object. The same HTML and CSS are used as in Example 5-1; you can access this example in the free download materials from www.wrox.com/go/webdevwithjquery. This example is named Example 5-2.

$(document).ready(

function()

{

var beatles = {

john : 'John Lennon',

paul : 'Paul McCartney',

george : 'George Harrison',

ringo : 'Ringo Starr'

};

var ul = $('ul#beatles');

// each() called via jQuery

$(beatles).each(

function()

{

ul.append('<li>' + this + '</li>');

}

);

var albums = {

1 : 'Please Please Me',

2 : 'With the Beatles',

3 : 'A Hard Day\'s Night',

4 : 'Beatles for Sale',

5 : 'Help!',

6 : 'Rubber Soul',

7 : 'Revolver',

8 : 'Sgt. Pepper\'s Lonely Hearts Club Band',

9 : 'Magical Mystery Tour',

10 : 'The Beatles',

11 : 'Yellow Submarine',

12 : 'Abbey Road',

13 : 'Let It Be'

};

ul = $('ul#beatlesAlbums');

if (albums instanceof Array)

{

console.log("Albums is an array.");

}

else

{

console.log("Albums is a plain object.");

}

// each() called directly.

$.each(

albums,

function()

{

ul.append('<li>' + this + '</li>');

}

);

}

);

In the preceding example you pass an object to jQuery directly and then try to enumerate the object with a call to each(). In Figure 5.2, you can see that the enumeration is not successful. You find that only one item called [object Object]. This means that jQuery passed an object to each(), instead of looking at each of the four properties attached to the object.

image

Figure 5.2

jQuery can enumerate objects, however, as you can see that the second object is enumerated successfully when the object is passed directly to the each() method as its first argument. If an object is an array, you'll find that the expression (variable instanceof Array)evaluates to true. In this case, the object is not an instanceof Array, so the expression evaluates to false, and the text “Albums is a plain object.” is written to the JavaScript console.

NOTE Emulating the functionality of the break and continue keywords using jQuery's each() method is handled in a very intuitive way. All you have to do is write a return statement in your callback function. Returning false from your callback function stops iteration, just like using a break keyword in a normal loop, and returning true continues iteration to the next item immediately, just like using a continue keyword.

Iterating a Selection

jQuery's each() method doesn't have to be applied to an array or object, however; it can also be applied to a selection of elements. The following document, Example 5-3, demonstrates how each() can be used to iterate over a selection of elements:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>Rubber Soul</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-3.js'></script>

<link href='Example 5-3.css' rel='stylesheet' />

</head>

<body>

<h4>Rubber Soul</h4>

<ul id='rubberSoul'>

<li>Drive My Car</li>

<li>Norwegian Wood (This Bird Has Flown)</li>

<li>You Won't See Me</li>

<li>Nowhere Man</li>

<li>Think for Yourself</li>

<li>The Word</li>

<li>Michelle</li>

<li>What Goes On</li>

<li>Girl</li>

<li>I'm Looking Through You</li>

<li>In My Life</li>

<li>Wait</li>

<li>If I Needed Someone</li>

<li>Run for Your Life</li>

</ul>

</body>

</html>

The following style sheet is applied to the preceding markup document:

body {

font: 12px "Lucida Grande", Arial, sans-serif;

color: rgb(50, 50, 50);

margin: 0;

padding: 0 10px;

}

ul {

list-style: none;

margin: 0 0 10px 0;

padding: 10px;

background: yellow;

width: 250px;

}

ul li {

padding: 3px;

}

h4 {

margin: 10px 0;

}

li.rubberSoulEven {

background: lightyellow;

}

In the following script, you see that jQuery's each() method can be chained onto a selection like any other method, and you can iterate over the items of the selection:

$(document).ready(

function()

{

$('ul#rubberSoul li').each(

function(key)

{

if (key & 1)

{

$(this).addClass('rubberSoulEven');

}

}

);

}

);

Iterating a selection is essentially the same as iterating an array, only this time when you're working with the callback function, the this keyword contains an individual element from the selection. If you want to use jQuery methods within the callback function, you'll have to wrap the this keyword with a call to the dollar sign method. In the example, each <li> element is selected, iterated using the each() method, and then the even numbered ones are given the class name rubberSoulEven. Figure 5.3 shows the preceding example in a browser.

image

Figure 5.3

Filtering Selections and Arrays

Two methods can be associated with filtering an array or a selection in jQuery's API. One method is called filter(), and it is used for filtering items from a selection exclusively. The other method is called grep(), and it is used for filtering items from an array exclusively.

Filtering a Selection

The filter()method removes items from a selection using a selector or a callback function. The following document, Example 5-4, demonstrates how filter() can use a selector to reduce items in a selection, and how the end() method can remove a previously used filter:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>Rubber Soul</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-4.js'></script>

<link href='Example 5-4.css' rel='stylesheet' />

</head>

<body>

<h4>Rubber Soul</h4>

<ul id='rubberSoul'>

<li class='Paul'>Drive My Car</li>

<li class='John'>Norwegian Wood (This Bird Has Flown)</li>

<li class='Paul'>You Won't See Me</li>

<li class='John'>Nowhere Man</li>

<li class='George'>Think for Yourself</li>

<li class='John'>The Word</li>

<li class='Paul'>Michelle</li>

<li class='John'>What Goes On</li>

<li class='John'>Girl</li>

<li class='Paul'>I'm Looking Through You</li>

<li class='John'>In My Life</li>

<li class='John'>Wait</li>

<li class='George'>If I Needed Someone</li>

<li class='John'>Run for Your Life</li>

</ul>

</body>

</html>

The preceding markup document includes the following style sheet:

body {

font: 12px "Lucida Grande", Arial, sans-serif;

color: rgb(50, 50, 50);

margin: 0;

padding: 0 10px;

}

ul {

list-style: none;

margin: 0 0 10px 0;

padding: 10px;

background: yellow;

width: 250px;

}

ul li {

padding: 3px;

}

h4 {

margin: 10px 0;

}

li.rubberSoulJohn {

background: lightblue;

}

li.rubberSoulPaul {

background: lightgreen;

}

li.rubberSoulGeorge {

background: lightyellow;

}

The following script demonstrates how the filter() method uses a selector to indicate which items should be in the selection:

$(document).ready(

function()

{

$('ul#rubberSoul li')

.filter('li.George')

.addClass('rubberSoulGeorge')

.end()

.filter('li.John')

.addClass('rubberSoulJohn')

.end()

.filter('li.Paul')

.addClass('rubberSoulPaul')

.end();

}

);

In the preceding script, the selector li.George reduces the selection to include only the <li> elements that have a class name of George; then the class name rubberSoulGeorge is added to each of those <li> elements, and the same happens for Paul and John. Just before the time a new filter() is attempted, a call to end() removes the last filter applied to the selection. Figure 5.4 shows this example in Safari.

image

Figure 5.4

Filtering a Selection with a Callback Function

Like each(), the filter() method can be used with a callback function. When it is used in this way, filter() is similar to each(), in that it allows a callback function to be specified that is subsequently executed once for every item present in a selection.

With the each() method, you learned that returning a boolean value simulates continue and break statements. With the filter() method, returning a boolean value decides whether an item should be kept or removed from the selection. Returning true keeps the item in the selection, and returning false removes the item from the selection. Using filter() with a callback function is demonstrated in the following document, Example 5-5:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>Rubber Soul</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-5.js'></script>

<link href='Example 5-5.css' rel='stylesheet' />

</head>

<body>

<h4>Rubber Soul</h4>

<ul id='rubberSoul'>

<li class='Paul'>Drive My Car</li>

<li class='John'>Norwegian Wood (This Bird Has Flown)</li>

<li class='Paul'>You Won't See Me</li>

<li class='John'>Nowhere Man</li>

<li class='George'>Think for Yourself</li>

<li class='John'>The Word</li>

<li class='Paul'>Michelle</li>

<li class='John'>What Goes On</li>

<li class='John'>Girl</li>

<li class='Paul'>I'm Looking Through You</li>

<li class='John'>In My Life</li>

<li class='John'>Wait</li>

<li class='George'>If I Needed Someone</li>

<li class='John'>Run for Your Life</li>

</ul>

</body>

</html>

The preceding markup document links to the following style sheet:

body {

font: 12px "Lucida Grande", Arial, sans-serif;

color: rgb(50, 50, 50);

margin: 0;

padding: 0 10px;

}

ul {

list-style: none;

margin: 0 0 10px 0;

padding: 10px;

background: yellow;

width: 250px;

}

ul li {

padding: 3px;

}

h4 {

margin: 10px 0;

}

li.rubberSoulJohnAndPaul {

background: lightblue;

}

The following script demonstrates how jQuery's filter() method can use a callback function to reduce items present in a selection:

$(document).ready(

function()

{

$('ul#rubberSoul li')

.filter(

function()

{

return $(this).hasClass('John') || $(this).hasClass('Paul');

}

)

.addClass('rubberSoulJohnAndPaul');

}

);

In the preceding script, the filter() method iterates over each item present in the original selection. It looks at each individual <li> element and checks to see if the <li> element has a class name of John or a class name of Paul; if either class name is present, the callback function returns true, indicating that the item should be kept in the selection. Each item kept in the selection then receives a class name of rubberSoulJohnAndPaul. Figure 5.5 shows a screenshot of this example in Safari. Each song written primarily by John or Paul has a lightblue background.

Filtering an Array

As indicated previously, arrays are filtered using a different method called grep(), which can be called only directly, which is to say, you may call it only as $.grep() or jQuery.grep(). Wrapping an array in the dollar sign method and then calling grep() doesn't work for this utility method. The grep() method would typically be used to directly filter some arbitrary array of items in code, rather than a selection from the DOM because the filter() method already exists explicitly for filtering selections. The following example, Example 5-6, demonstrates how grep() is used to filter arrays by creating an array of items from a selection; this is done simply to demonstrate how grep() works:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>Rubber Soul</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-6.js'></script>

<link href='Example 5-6.css' rel='stylesheet' />

</head>

<body>

<h4>Rubber Soul</h4>

<ul id='rubberSoul'>

<li class='Paul'>Drive My Car</li>

<li class='John'>Norwegian Wood (This Bird Has Flown)</li>

<li class='Paul'>You Won't See Me</li>

<li class='John'>Nowhere Man</li>

<li class='George'>Think for Yourself</li>

<li class='John'>The Word</li>

<li class='Paul'>Michelle</li>

<li class='John'>What Goes On</li>

<li class='John'>Girl</li>

<li class='Paul'>I'm Looking Through You</li>

<li class='John'>In My Life</li>

<li class='John'>Wait</li>

<li class='George'>If I Needed Someone</li>

<li class='John'>Run for Your Life</li>

</ul>

<ul id='rubberSoulFiltered'>

</ul>

</body>

</html>

image

Figure 5.5

The preceding markup document is linked to the following style sheet:

body {

font: 12px "Lucida Grande", Arial, sans-serif;

color: rgb(50, 50, 50);

margin: 0;

padding: 0 10px;

}

ul {

list-style: none;

margin: 0 0 10px 0;

padding: 10px;

background: yellow;

width: 250px;

}

ul li {

padding: 3px;

}

h4 {

margin: 10px 0;

}

li.rubberSoulJohnAndPaul {

background: lightblue;

}

ul#rubberSoulFiltered {

display: none;

}

The following script demonstrates the grep() method:

$(document).ready(

function()

{

var songs = [];

$('ul#rubberSoul li').each(

function()

{

songs.push(

$(this).text()

);

}

);

var filteredSongs = $.grep(

songs,

function(value, key)

{

return value.indexOf('You') != -1;

}

);

var ul = $('ul#rubberSoulFiltered');

$('ul#rubberSoul').hide();

ul.show();

$(filteredSongs).each(

function()

{

ul.append('<li>' + this + '</li>');

}

);

}

);

The preceding script begins by creating a new array and assigning that array to the variable songs. The script then selects all <li> elements within the <ul> element with id name rubberSoul and assigns the text of each <li> element as a new item in the songs array usingpush(). The end result is that the songs array contains the titles for all the songs on Rubber Soul.

Then, a new variable is created called filteredSongs, which contains a filtered array. The grep() method is called directly as $.grep(), with the songs array as the first argument and a callback function as the second argument. In the callback function, you return a boolean value to indicate whether each item should be kept in the array or removed. Returning true indicates that the value should be kept; returning false indicates that the item should be discarded. You can also change the value being kept as well—simply return the replacement value you want to use, and it replaces any previous value.

In the example, the callback function checks to see if each song title contains the word You, using JavaScript's indexOf() method. If it does, the song title is kept; if not, the song title is discarded.

The <ul> element with id name rubberSoul is hidden by selecting it and then making a call to jQuery's hide() method.

Finally, the script iterates over the new filteredSongs array using each(), and the four song titles containing the word you are appended as new <li> elements to the <ul> element with id name rubberSoulFiltered. Figure 5.6 shows the results of the preceding example in a browser.

image

Figure 5.6

The grep() method also allows an optional third argument called invert to be specified; if it is set to true, the values of the filtered array are reversed.

NOTE The arguments provided to the $.grep() callback function are reversed; value is the first argument and key is the second. In addition, the value argument is not also provided within this when using $.grep().

Mapping a Selection or an Array

As was the case with filtering, there are two different contexts in which you can map one collection of items to another, in a selection or with an arbitrary array of items. This time, however, both contexts use a function that goes by the same name, map(). In the following sections, you learn more about the map() method as applied within either context.

Mapping a Selection

The concept of mapping is taking one set of values and modifying one or more of those values to create a new set of values. No items are removed from the set during a mapping, so it's expected that you'll have a set of values of the same length when you finish mapping as when you started—the idea being more or less that you can arbitrarily replace values as needed with new ones that have redundant modifications that must be made to some or all values. The following document, Example 5-7, demonstrates how you map a selection with jQuery:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>Rubber Soul</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-7.js'></script>

<link href='Example 5-7.css' rel='stylesheet' />

</head>

<body>

<h4>Rubber Soul</h4>

<ul id='rubberSoul'>

<li class='Paul'>Drive My Car</li>

<li class='John'>Norwegian Wood (This Bird Has Flown)</li>

<li class='Paul'>You Won't See Me</li>

<li class='John'>Nowhere Man</li>

<li class='George'>Think for Yourself</li>

<li class='John'>The Word</li>

<li class='Paul'>Michelle</li>

<li class='John'>What Goes On</li>

<li class='John'>Girl</li>

<li class='Paul'>I'm Looking Through You</li>

<li class='John'>In My Life</li>

<li class='John'>Wait</li>

<li class='George'>If I Needed Someone</li>

<li class='John'>Run for Your Life</li>

</ul>

<ul id='rubberSoulMapped'>

</ul>

</body>

</html>

The preceding markup document is styled with the following style sheet:

body {

font: 12px "Lucida Grande", Arial, sans-serif;

color: rgb(50, 50, 50);

margin: 0;

padding: 0 10px;

}

ul {

list-style: none;

margin: 0 0 10px 0;

padding: 10px;

background: yellow;

width: 350px;

}

ul li {

padding: 3px;

}

h4 {

margin: 10px 0;

}

ul#rubberSoulMapped {

display: none;

}

The following script demonstrates how a selection is mapped to a new array:

$(document).ready(

function()

{

var mappedSongs = $('ul#rubberSoul li').map(

function(key)

{

if ($(this).hasClass('John'))

{

return $(this).text() + ' <i>John Lennon</i>';

}

if ($(this).hasClass('Paul'))

{

return $(this).text() + ' <i>Paul McCartney</i>';

}

if ($(this).hasClass('George'))

{

return $(this).text() + ' <i>George Harrison</i>';

}

}

);

$('ul#rubberSoul').hide();

var ul = $('ul#rubberSoulMapped');

ul.show();

$(mappedSongs).each(

function()

{

ul.append('<li>' + this + '</li>');

}

);

}

);

The preceding script begins by selecting all <li> elements in the document. Then a call to the map() method is chained onto that selection, and a callback function is provided as the first argument to the map() method.

The callback function provided to the map() method, as with the other methods you've observed in this chapter, passes each item to its callback function in the this keyword. If you need to reference it, the index or key or counter (whatever you choose to call it) is accessible in the first argument that you provide to your callback function. Each item is numbered offset from zero, and that counter is accessible in that first argument. In the preceding example, the first argument is named key.

Inside the callback function, a few expressions look to see what class name each <li> element has. If the <li> element has a class name of John, for example, the callback function returns the name of the song with the HTML <i>John Lennon</i> appended to the end. The callback function attaches the name of the more prominent writer of each song for each song present, building a new array that is assigned to the variable mappedSongs.

The first <ul> list with id name rubberSoul is hidden by selecting it and making a call to jQuery's hide() method and the <ul> with id name rubberSoulMapped is displayed with a call to show().

The each() method is then used to iterate the contents of the mappedSongs variable, appending each mapped value to the second <ul> element with the id name rubberSoulMapped. Figure 5.7 shows the final product.

Mapping an Array

Mapping an array basically employs the same logic that you observed in Example 5-7 with mapping a selection—you just use an array instead of a selection. So, you can call jQuery's map() method with an array the same way that you called the each() method, by either passing an array to the dollar sign method or by calling the map() method directly, with an array as its first argument and a callback function as its second argument. The following document, Example 5-8, shows an example of the map() method as it is applied to an array:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>Revolver</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-8.js'></script>

<link href='Example 5-8.css' rel='stylesheet' />

</head>

<body>

<h4>Revolver</h4>

<ul id='revolver'>

</ul>

</body>

</html>

image

Figure 5.7

The following style sheet is applied to the preceding markup:

body {

font: 12px "Lucida Grande", Arial, sans-serif;

color: rgb(50, 50, 50);

margin: 0;

padding: 0 10px;

}

ul {

list-style: none;

margin: 0 0 10px 0;

padding: 10px;

background: yellow;

width: 350px;

}

ul li {

padding: 3px;

}

h4 {

margin: 10px 0;

}

The following script demonstrates how jQuery's map() method is used with an array instead of a selection:

$(document).ready(

function()

{

var songs = [

'Taxman',

'Eleanor Rigby',

'I\'m Only Sleeping',

'Love You To',

'Here, There and Everywhere',

'Yellow Submarine',

'She Said, She Said',

'Good Day Sunshine',

'And Your Bird Can Sing',

'For No One',

'Doctor Robert',

'I Want to Tell You',

'Got to Get You into My Life',

'Tomorrow Never Knows'

];

var mappedSongs = $(songs).map(

function(key)

{

var track = key + 1;

return (track < 10? '0' + track : track) + ' ' + this;

}

);

$(mappedSongs).each(

function()

{

$('ul#revolver').append('<li>' + this + '</li>');

}

);

}

);

In the preceding script, a collection of song titles of the Beatles' album Revolver is placed in an array and assigned to the variable songs.

The songs variable is then passed to a call to the dollar sign method, and the map() method is called.

In the callback function passed to the map() method, a variable called track is created by incrementing the key's value by one; it's used as a counter for the track number. The callback function then checks to see if track is less than 10 using a ternary expression. If it is, a leading zero is prepended to the value; otherwise, no leading zero is prepended. This portion becomes the track number.

A single space is inserted between the track number and the song title, and the new array containing song titles with track numbers prefixed is assigned to the variable mappedSongs.

Finally, the array assigned to the mappedSongs variable is iterated using the each() method, and the modified song titles with track name prefixes are appended as <li> elements to the <ul> element in the document. The result of the preceding example appears in Figure 5.8.

image

Figure 5.8

Array Utility Methods

jQuery also provides a few utility methods that are useful for probing information from an array. The following sections briefly cover each of jQuery's utility methods:

· $.makeArray(data)—Transforms any data into a true array

· $.inArray(needle, haystack)—Finds the index associated with the first occurrence of needle within the haystack

· $.merge(first, second)—Merges two arrays together

Most of jQuery's array utility methods must be called directly, using the dollar sign dot function name, as you see documented in the preceding list. All the methods covered in this chapter are documented in the Quick Reference that appears in Appendix I, “Utilities,” as well as Appendix C, “Selecting, Traversing, and Filtering.” Appendix I contains utility methods, and Appendix C contains jQuery methods that exist for filtering or traversing a selection.

Making an Array

jQuery's makeArray() method does just what the name implies; it takes any data and transforms it into a true array. The following example, Example 5-9, shows how a string, an object, or a number can be made into an array using this method:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>$.makeArray()</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-9.js'></script>

</head>

<body>

</body>

</html>

The following JavaScript is included in the preceding markup document.

$(document).ready(

function()

{

var name = 'The Beatles';

var madeArray = $.makeArray(name);

console.log('Transforming a string.');

console.log('Type: ' + typeof(madeArray));

console.log('Is Array? ' + (madeArray instanceof Array? 'yes' : 'no'));

console.log(madeArray);

var madeArray = {

band1 : "The Beatles",

band2 : "Electric Light Orchestra",

band3 : "The Moody Blues",

band4 : "Radiohead"

};

madeArray = $.makeArray(madeArray);

console.log('Transforming an object.');

console.log('Type: ' + typeof(madeArray));

console.log('Is Array? ' + (madeArray instanceof Array? 'yes' : 'no'));

console.log(madeArray);

var madeArray = 1;

madeArray = $.makeArray(madeArray);

console.log('Transforming a number.');

console.log('Type: ' + typeof(madeArray));

console.log('Is Array? ' + (madeArray instanceof Array? 'yes' : 'no'));

console.log(madeArray);

}

);

The preceding code writes data to the JavaScript console like that shown in Figure 5.9.

image

Figure 5.9

In the script, the string The Beatles is assigned to the variable name. The variable name is passed to makeArray(), and the result is assigned to the variable madeArray. Then, you check the typeof of the object madeArray, which will be object now instead of string. The expression madeArray instanceof Array will also report true, and then the content of madeArray is dumped to the console for visual inspection.

The process is repeated for an object and a number, each time resulting in an array.

Finding a Value Within an Array

jQuery's inArray() method works just like JavaScript's indexOf() method. It returns the position of an item within an array. If it is present, offset from zero, and if the item is not present, the function returns –1 (minus one). The following example, Example 5-10, demonstrates how jQuery's inArray() method works:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>$.inArray()</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-10.js'></script>

</head>

<body>

</body>

</html>

The following JavaScript demonstrates $.inArray():

$(document).ready(

function()

{

var songs = [

'Taxman',

'Eleanor Rigby',

'I\'m Only Sleeping',

'Love You To',

'Here, There and Everywhere',

'Yellow Submarine',

'She Said, She Said',

'Good Day Sunshine',

'And Your Bird Can Sing',

'For No One',

'Doctor Robert',

'I Want to Tell You',

'Got to Get You into My Life',

'Tomorrow Never Knows'

];

console.log(

'Love You To: ' + (

$.inArray('Love You To', songs)

)

);

console.log(

'Strawberry Fields Forever: ' + (

$.inArray('Strawberry Fields Forever', songs)

)

);

}

);

The preceding script outputs the messages to the console, as shown in Figure 5.10.

image

Figure 5.10

Merging Two Arrays

jQuery's $.merge() method can glue two arrays together to make a single array. The following example, Example 5-11, demonstrates how this works:

<!DOCTYPE HTML>

<html lang='en'>

<head>

<meta http-equiv='X-UA-Compatible' content='IE=Edge' />

<meta charset='utf-8' />

<title>$.merge()</title>

<script src='../jQuery.js'></script>

<script src='../jQueryUI.js'></script>

<script src='Example 5-11.js'></script>

</head>

<body>

</body>

</html>

The following script is included in the preceding markup:

$(document).ready(

function()

{

var rubberSoul = [

'Drive My Car',

'Norwegian Wood (This Bird Has Flown)',

'You Won\'t See Me',

'Nowhere Man',

'Think for Yourself',

'The Word',

'Michelle',

'What Goes On',

'Girl',

'I\'m Looking Through You',

'In My Life',

'Wait',

'If I Needed Someone',

'Run for Your Life'

];

var revolver = [

'Taxman',

'Eleanor Rigby',

'I\'m Only Sleeping',

'Love You To',

'Here, There and Everywhere',

'Yellow Submarine',

'She Said, She Said',

'Good Day Sunshine',

'And Your Bird Can Sing',

'For No One',

'Doctor Robert',

'I Want to Tell You',

'Got to Get You into My Life',

'Tomorrow Never Knows'

];

var songs = $.merge(rubberSoul, revolver);

console.log('Songs :', songs);

}

);

The preceding script results in the console output that you see in Figure 5.11.

image

Figure 5.11

As you can see, jQuery's merge() method is pretty straightforward, appending the contents of the second array argument to the contents of the first array argument.

Summary

This chapter presented several methods associated with iterating and working with arrays and selections.

You learned how jQuery's each() method is a less-verbose, easier-to-use alternative for iterating over an array, object, or selection when compared to using a for construct and a counter, or a for/in construct for objects. You learned how to emulate break and continuekeywords with the each() method by returning a boolean value. You learned that jQuery's each() method can be called directly or chained to a selection or an array that's wrapped in a call to the dollar sign method.

You learned how a selection is filtered using jQuery's filter() method using either a selector or a callback function. An array can be filtered using jQuery's grep() method, which must be called directly.

You learned how one array can be mapped to another array and how one selection can be mapped to an array using jQuery's map() method, which exists to translate one set of values to another set of values.

Finally, you learned about jQuery's various array utility methods. $.makeArray() can turn any data into a true array. $.inArray() can find the position of a value within an array, offset from zero, and works just like JavaScript's indexOf() method, with –1 (minus one) indicating that a value is not present within the array. $.merge() glues two separate arrays together into just one array.

Exercises

1. What might the JavaScript code look like if you want to iterate over the following collection of elements using jQuery's each() method?

nodes = document.getElementsByTagName('div');

2. What statement would you write inside a callback function provided to jQuery's each() method if you want to simulate a break statement?

3. When filtering a selection using filter(), what does providing a selector to the filter() method do?

4. When filtering a selection using filter() with a callback function, what does returning true do?

5. What value does a callback function provided to jQuery's grep() method have to return to keep an item in the array?

6. What happens to the value returned by a callback function provided to jQuery's map() method?

7. What does –1 (minus one) mean when returned by jQuery's $.inArray() method?