Skip to content
This repository has been archived by the owner on May 26, 2019. It is now read-only.

Improve Object Model section #555

Merged
merged 7 commits into from
Aug 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions data/pages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
- title: "The Object Model"
url: 'object-model'
pages:
- title: "Objects in Ember"
url: "index"
- title: "Classes and Instances"
url: "classes-and-instances"
- title: "Reopening Classes and Instances"
Expand All @@ -30,8 +32,6 @@
url: "observers"
- title: "Bindings"
url: "bindings"
- title: "Bindings, Observers, Computed Properties: What Do I Use When?"
url: "what-do-i-use-when"
- title: "Enumerables"
url: 'enumerables'

Expand Down
9 changes: 4 additions & 5 deletions source/object-model/bindings.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
A binding creates a link between two properties such that when one changes, the
other one is updated to the new value automatically. Bindings can connect
properties on the same object, or across two different objects. Unlike most other
frameworks that include some sort of binding implementation, bindings in
Ember.js can be used with any object, not just between views and models.
Unlike most other frameworks that include some sort of binding implementation,
bindings in Ember.js can be used with any object. That said, bindings are most
often used within the Ember framework itself, and for most problems Ember app
developers face, computed properties are the appropriate solution.

The easiest way to create a two-way binding is to use a computed alias, that
specifies the path to another object.
Expand Down
12 changes: 8 additions & 4 deletions source/object-model/classes-and-instances.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
As you learn about Ember, you'll see code like `Ember.Component.extend()` and
`DS.Model.extend()`. Here, you'll learn about this `extend()` method, as well
as other major features of the Ember object model.

### Defining Classes

To define a new Ember _class_, call the `extend()` method on
Expand All @@ -17,10 +21,10 @@ You can also create a _subclass_ from any existing class by calling
its `extend()` method. For example, you might want to create a subclass
of Ember's built-in `Ember.Component` class:

```app/views/person.js
PersonView = Ember.Component.extend({
tagName: 'li',
classNameBindings: ['isAdministrator']
```app/components/todo-item.js
export default Ember.Component.extend({
classNameBindings: ['isUrgent'],
isUrgent: true
});
```

Expand Down
99 changes: 32 additions & 67 deletions source/object-model/enumerables.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
## Enumerables

In Ember.js, an Enumerable is any object that contains a number of child
objects, and which allows you to work with those children using the
[Ember.Enumerable](http://emberjs.com/api/classes/Ember.Enumerable.html) API. The most common
Expand All @@ -16,51 +14,37 @@ possible. This minimizes incompatibility with other libraries, and
allows Ember.js to use the native browser implementations in arrays
where available.

For instance, all Enumerables support the standard `forEach` method:

```javascript
[1,2,3].forEach(function(item) {
console.log(item);
});

//=> 1
//=> 2
//=> 3
```

In general, Enumerable methods, like `forEach`, take an optional second
parameter, which will become the value of `this` in the callback
function:

```javascript
var array = [1,2,3];

array.forEach(function(item) {
console.log(item, this.indexOf(item));
}, array)

//=> 1 0
//=> 2 1
//=> 3 2
```

### Enumerables in Ember.js

Usually, objects that represent lists implement the Enumerable interface. Some examples:

* **Array** - Ember extends the native JavaScript `Array` with the
Enumerable interface (unless you [disable prototype
extensions.](../../configuring-ember/disabling-prototype-extensions))
* **Ember.Set** - A data structure that can efficiently answer whether it
includes an object.

### API Overview

In this guide, we'll explore some of the most common Enumerable
## Use of Observable Methods

In order for Ember to observe when you make a change to an enumerable, you need
to use special methods that Ember.Enumerable provides. For example, if you add
an element to an array using the standard JavaScript method `push`, Ember will
not be able to observe the change, but if you use the Enumerable method
`pushObject`, the change will propagate throughout your application.

Here is a list of standard JavaScript array methods and their observable
Enumerable equivalents:

<table>
<thead>
<tr><th>Standard Method</th><th>Observable Equivalent</th></tr>
</thead>
<tbody>
<tr><td>pop</td><td>popObject</td></tr>
<tr><td>push</td><td>pushObject</td></tr>
<tr><td>reverse</td><td>reverseObjects</td></tr>
<tr><td>shift</td><td>shiftObject</td></tr>
<tr><td>unshift</td><td>unshiftObject</td></tr>
</tbody>
</table>

## API Overview

In the rest of this guide, we'll explore some of the most common Enumerable
conveniences. For the full list, please see the [Ember.Enumerable API
reference documentation.](http://emberjs.com/api/classes/Ember.Enumerable.html)

#### Iterating Over an Enumerable
### Iterating Over an Enumerable

To enumerate all the values of an enumerable object, use the `forEach` method:

Expand All @@ -76,25 +60,7 @@ food.forEach(function(item, index) {
// Menu Item 3: Adobo Chicken
```

#### Making an Array Copy

You can make a native array copy of any object that implements
`Ember.Enumerable` by calling the `toArray()` method:

```javascript
var states = Ember.Set.create();

states.add("Hawaii");
states.add("California")

states.toArray()
//=> ["Hawaii", "California"]
```

Note that in many enumerables, such as the `Ember.Set` used in this
example, the order of the resulting array is not guaranteed.

#### First and Last Objects
### First and Last Objects

All Enumerables expose `firstObject` and `lastObject` properties
that you can bind to.
Expand All @@ -111,7 +77,7 @@ animals.get('lastObject');
//=> "peacock"
```

#### Map
### Map

You can easily transform each item in an enumerable using the
`map()` method, which creates a new array with results of calling a
Expand Down Expand Up @@ -145,7 +111,7 @@ states.mapBy('capital');
//=> ["Honolulu", "Sacramento"]
```

#### Filtering
### Filtering

Another common task to perform on an Enumerable is to take the
Enumerable as input, and return an Array after filtering it based on
Expand Down Expand Up @@ -185,7 +151,7 @@ todos.filterBy('isDone', true);

If you want to return just the first matched value, rather than an Array containing all of the matched values, you can use `find` and `findBy`, which work just like `filter` and `filterBy`, but return only one item.

#### Aggregate Information (All or Any)
### Aggregate Information (All or Any)

If you want to find out whether every item in an Enumerable matches some condition, you can use the `every` method:

Expand Down Expand Up @@ -223,4 +189,3 @@ Just like the filtering methods, the `every` and `some` methods have analogous `
people.isEvery('isHappy', true) // false
people.isAny('isHappy', true) // true
```

16 changes: 16 additions & 0 deletions source/object-model/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
You'll soon notice that standard JavaScript objects aren't used widely in Ember,
except as key-value pairs (often referred to as _hashes_). This is because
JavaScript objects don't support the ability to observe when an object changes,
which Ember needs to update data throughout an application.
Ember's object model builds on standard JavaScript objects to enable this
functionality, as well as bring several features like mixins and initialization
to make working with them a more pleasant experience. Although these features
aren't available in standard JavaScript, many of them are designed to align with
proposed additions to the ECMAScript standard.

In addition to bringing its own object model, Ember also extends the built-in
JavaScript `Array` prototype with its Enumerable interface to enable it to
observe changes and provide more features.

Finally, Ember extends the `String` prototype with a few [formatting and
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we mention somewhere that prototype extensions are disabled in addons? or that's for the ember-cli addons documentation, or?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the goal is to move away from talking about prototype extensions in an effort to get people to also move away from using them #457 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a related but separate issue @HeroicEric, I'm fine with the PR as it is.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@locks I just figured that since this is new content it, it might be better to not add more references to prototype extensions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My takeaway from #110 was that we are discourage use of Function prototype extensions but were okay with Array prototype extensions, at least for now. If I misunderstood or there's been other discussion since, just let me know!

Re: addons, I think that's a separate story, and should go in the guide for authoring addons when it's written.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelrkn I know the goal to eventually move away from extending Array but it looks like there is a good amount of work left (emberjs/ember.js#10899) before that will happen. And I do think that part about the arrays is still useful to know because you're likely to run into them with current state of things, so I'm not totally against that part.

IMO, the part about String prototype extensions is less important to tell them about. I think it would be better to encourage using Ember.String.foo whenever possible.

That being said, I can always open another issue about this to discuss it further without blocking this PR 😄

localization methods](http://emberjs.com/api/classes/Ember.String.html).
9 changes: 9 additions & 0 deletions source/object-model/observers.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
Ember supports observing any property, including computed properties.

Observers should contain behavior that reacts to changes in another property.
Observers are especially useful when you need to perform some behavior after a
binding has finished synchronizing.

Observers are often over-used by new Ember developers. Observers are used
heavily within the Ember framework itself, but for most problems Ember app
developers face, computed properties are the appropriate solution.

You can set up an observer on an object by using `Ember.observer`:

```javascript
Expand Down
21 changes: 0 additions & 21 deletions source/object-model/what-do-i-use-when.md

This file was deleted.