The
Ember.Enumerable
methods are very important when dealing with arrays. In these recipes, we'll look at some common use cases.
To understand how to use enumerables, we must first take a look at the standard JavaScript array methods and their equivalents using observable enumerables:
Standard method |
Observable equivalent |
---|---|
|
|
|
|
|
|
|
|
|
|
We'll be using some of these methods in our examples, so keep in mind what the standard and observable equivalents are.
The Ember.Enumerable
class has several methods that we can use in our Ember applications. Here is the list of the more common methods and what they do:
Enumerable method |
Definition |
---|---|
|
This iterates through the enumerable, calling the passed function on each item |
|
This returns the first object in a collection |
|
This returns the last object in a collection |
|
This maps all the items in the enumeration to another value, similar to map in JavaScript 1.6 |
|
Similar to map, this returns the value of the named property on all items on the enumeration |
|
This returns an array with all of the items in the enumeration that the passed function returns true |
|
This returns the first item in the array that the method returns true |
|
This returns the first item with a property that matches the passed value |
|
This returns true only if the passed function returns true for every item in the enumeration |
|
This returns true only if the passed function returns true for any item in the enumeration |
Many of these methods are similar to their JavaScript counterparts. If you know how to use the JavaScript method, you should be able to use the Ember equivalent as well.
Ember.Enumerables
adds all the nice features of Ember objects to enumerables. We'll take a look at several examples on how to do this. The contents for all these recipes are in the chapter2/example6
folder in the app.js
file.
A very common use case for an enumerable is iterating over an array with forEach
.
const students = ['Erik', 'Jim', 'Shelly', 'Kate'];
forEach
enumerable to iterate over the array:students.forEach(function(item, index) { console.log(`Student #${index+1}: ${item}`); });
The console output will show each student's name in the array:
Student #1: Erik Student #2: Jim Student #3: Shelly Student #4: Kate
Template literals
Ember is compatible with the latest in ECMAScript 2015. One neat new feature is called template literals or template strings. Template literals are string literals that can stretch across multiple lines and include interpolated expressions. You can do string interpolation by surrounding variables in your strings, like this ${}
. Each variable will be displayed in the string as shown in the preceding forEach
example.
The map
method takes an array, maps each item, and returns a new modified array. Let's say that we want to make the student names all in uppercase. We can do this using map
.
students
:const students = ['Erik', 'Jim', 'Shelly', 'Kate'];
The first letter is capitalized; however, we want all the letters in uppercase.
map
to convert every item to uppercase:const upperCaseStudent= students.map(function(item) { return item.toUpperCase(); });
Every item in the array has been converted to uppercase. The new upperCaseStudent
array has all the new values.
forEach
enumerable to iterate through every item in the array and display its contents:upperCaseStudent.forEach(function(item, index) { console.log(`student #${index+1}: ${item}`); });
The output displays each name in the new upperCaseStudent
array:
student #1: ERIK student #2: JIM student #3: SHELLY student #4: KATE
The mapBy
enumerable can be used if your array is comprised of objects. From each object, we can extract its named properties and return a new array.
const student = Ember.Object.extend({ name: 'Erik Hanchett' }); const teacher = Ember.Object.extend({ name: 'John P. Smith' });
Each object has one property called name
:
const t= teacher.create(); const s = student.create(); const people = [s, t];
mapBy
to create a new array.console.log(people.mapBy('name'));//['Erik Hanchett', 'John P. Smith']
This new array returned has the values from the name
property from both objects.
If necessary, we have an easy way to grab the first and last objects in an array.
const students = ['Erik', 'Jim', 'Shelly', 'Kate', 'Jenny', 'Susan'];
This array has six different students.
console.log(students.get('lastObject')); //Susan
This will display Susan
, the last object in the array.
console.log(students.get('firstObject')); //Erik
This will display Erik
, the first item in the array.
students.pushObject('Jeff');
Jeff
has now been added to the list:console.log(students.get('lastObject')); //Jeff
A very common practice is to take an array and return a filtered list of items.
const array = [1,2,5,10,25,23];
array
and filter
it, returning only those numbers over 10
:const newArray =array.filter(function(item, index, self) { return item > 10; })
console.log
to display the new array:console.log(newArray); //[25,23]
This new array has numbers only greater then 10 in it.
With filterBy
, you can take a collection of objects and filter it by some property.
student
object that has a name
and grade
:const student = Ember.Object.extend({ grade: null, name: null });
const listOfStudents = [ student.create({grade: 'senior', name: 'Jen Smith'}), student.create({grade: 'sophmore', name: 'Ben Shine'}), student.create({grade: 'senior', name: 'Ann Cyrus'}) ];
filterBy
to show the students who are seniors:const newStudent = listOfStudents.filterBy('grade','senior');
This returns an array of students who are seniors.
forEach
:newStudent.forEach(function(item,index){ console.log(item.get('name')); }); Jen Smith Ann Cyrus
The find
enumerable works very similarly to
filter
except that it stops after finding the first match.
const array = [1,2,5,10,25,23];
array.find
to retrieve the first number in the list that is over 10
:const newArray =array.find(function(item, index){ return item > 10; });
console.log(newArray); //25
The answer is 25
as it's the first number in the list that is over 10.
The findBy
enumerable works very similarly to filterBy
except that it stops after finding the first match.
student
object:const student = Ember.Object.extend({ grade: null, name: null });
const listOfStudents = [ student.create({grade: 'senior', name: 'Jen Smith'}), student.create({grade: 'sophmore', name: 'Ben Shine'}), student.create({grade: 'senior', name: 'Ann Cyrus'}) ];
findBy
to match only the properties that have grade
of senior
:const newStudent = listOfStudents.findBy('grade','senior');
console.log(newStudent.get('name')); //Jen Smith
Jen Smith
is the first student who matches this criteria so it is returned to the newStudent
array.
The every
enumerable will return true
only if every item matches a certain condition.
const array = [11,25,23,30];
every
enumerable to check whether every item in the array is greater than 10
:console.log(array.every(function(item, index, self) { return item > 10; })); //returns true
This returns
true
because every item in the array is over 10
The any
enumerable will return true
if at least one item matches a certain condition.
const array = [1,2,5,10,25,23];
any
enumerable to check whether any of these numbers in this array are over 10
:console.log(array.any(function(item, index, self) { return item > 10; })); //returns true
This will return true
because at least one number is above 10
.
The Ember.Enumerable
mixin is Ember's implementation of the array API defined up to JavaScript 1.8. It's applied automatically on page load so any method is available. In order for Ember to be able to observe changes in an enumerable, you must use Ember.Enumerable
.
The enumerable API follows ECMAScript specifications as much as possible so it minimizes incompatibilities with the other libraries. It uses native browser implementations in arrays where available.