diff --git a/source/models/defining-models.md b/source/models/defining-models.md index e8a5c2538..c988f91a4 100644 --- a/source/models/defining-models.md +++ b/source/models/defining-models.md @@ -70,9 +70,9 @@ export default DS.Model.extend({ firstName: DS.attr(), lastName: DS.attr(), - fullName: function() { + fullName: Ember.computed('firstName', 'lastName', function() { return this.get('firstName') + ' ' + this.get('lastName'); - }.property('firstName', 'lastName') + }) }); ``` diff --git a/source/object-model/computed-properties-and-aggregate-data.md b/source/object-model/computed-properties-and-aggregate-data.md index 04b8d9b8d..b633e70ba 100644 --- a/source/object-model/computed-properties-and-aggregate-data.md +++ b/source/object-model/computed-properties-and-aggregate-data.md @@ -12,10 +12,10 @@ export default Ember.Controller.extend({ Ember.Object.create({ isDone: true }) ], - remaining: function() { + remaining: Ember.computed('todos.@each.isDone', function() { var todos = this.get('todos'); return todos.filterBy('isDone', false).get('length'); - }.property('todos.@each.isDone') + }) }); ``` diff --git a/source/object-model/computed-properties.md b/source/object-model/computed-properties.md index 4e8c755a9..42b49562e 100644 --- a/source/object-model/computed-properties.md +++ b/source/object-model/computed-properties.md @@ -2,7 +2,7 @@ In a nutshell, computed properties let you declare functions as properties. You create one by defining a computed property as a function, which Ember will automatically call when you ask for the property. You can then use it the same way you would any normal, static property. -It's super handy for taking one or more normal properties and transforming or manipulating their data to create a new value. +It's super handy for taking one or more normal properties and transforming or manipulating their data to create a new value. ### Computed properties in action @@ -14,9 +14,9 @@ Person = Ember.Object.extend({ firstName: null, lastName: null, - fullName: function() { + fullName: Ember.computed('firstName', 'lastName', function() { return this.get('firstName') + ' ' + this.get('lastName'); - }.property('firstName', 'lastName') + }) }); var ironMan = Person.create({ @@ -26,20 +26,28 @@ var ironMan = Person.create({ ironMan.get('fullName'); // "Tony Stark" ``` -Notice that the `fullName` function calls `property`. This declares the function to be a computed property, and the arguments tell Ember that it depends on the `firstName` and `lastName` attributes. + +This declares the function to be a computed property, and the arguments tell Ember that it depends on the `firstName` and `lastName` attributes. Whenever you access the `fullName` property, this function gets called, and it returns the value of the function, which simply calls `firstName` + `lastName`. #### Alternate invocation -At this point, you might be wondering how you are able to call the `.property` function on a function. This is possible because Ember extends the `function` prototype. More information about extending native prototypes is available in the [disabling prototype extensions guide](../../configuring-ember/disabling-prototype-extensions/). If you'd like to replicate the declaration from above without using these extensions you could do so with the following: +You might have seen computed properties written using the `.property` style +syntax: ```javascript - fullName: Ember.computed('firstName', 'lastName', function() { - return this.get('firstName') + ' ' + this.get('lastName'); - }) +fullName: function() { + return this.get('firstName') + ' ' + this.get('lastName'); +}.property('firstName', 'lastName') ``` +This is possible because Ember extends the `function` prototype. This is no +longer the recommended syntax. + +More information about native prototype extensions is available in the +[disabling prototype extensions guide](../../configuring-ember/disabling-prototype-extensions/). + ### Chaining computed properties You can use computed properties as values to create new computed properties. Let's add a `description` computed property to the previous example, and use the existing `fullName` property and add in some other properties: @@ -51,13 +59,13 @@ Person = Ember.Object.extend({ age: null, country: null, - fullName: function() { + fullName: Ember.computed('firstName', 'lastName', function() { return this.get('firstName') + ' ' + this.get('lastName'); - }.property('firstName', 'lastName'), + }), - description: function() { + description: Ember.computed('fullName', 'age', 'country', function() { return this.get('fullName') + '; Age: ' + this.get('age') + '; Country: ' + this.get('country'); - }.property('fullName', 'age', 'country') + }) }); var captainAmerica = Person.create({ @@ -72,7 +80,7 @@ captainAmerica.get('description'); // "Steve Rogers; Age: 80; Country: USA" ### Dynamic updating -Computed properties, by default, observe any changes made to the properties they depend on and are dynamically updated when they're called. Let's use computed properties to dynamically update. +Computed properties, by default, observe any changes made to the properties they depend on and are dynamically updated when they're called. Let's use computed properties to dynamically update. ```javascript captainAmerica.set('firstName', 'William'); diff --git a/source/object-model/observers.md b/source/object-model/observers.md index f69bb8f4b..50167b4a8 100644 --- a/source/object-model/observers.md +++ b/source/object-model/observers.md @@ -7,17 +7,17 @@ Person = Ember.Object.extend({ // these will be supplied by `create` firstName: null, lastName: null, - - fullName: function() { + + fullName: Ember.computed('firstName', 'lastName', function() { var firstName = this.get('firstName'); var lastName = this.get('lastName'); return firstName + ' ' + lastName; - }.property('firstName', 'lastName'), + }), - fullNameChanged: function() { + fullNameChanged: Ember.on(Ember.observer('fullName', function() { // deal with the change - }.observes('fullName').on('init') + }), 'init') }); var person = Person.create({ @@ -31,7 +31,6 @@ person.set('firstName', 'Brohuda'); // observer will fire Because the `fullName` computed property depends on `firstName`, updating `firstName` will fire observers on `fullName` as well. - ### Observers and asynchrony Observers in Ember are currently synchronous. This means that they will fire @@ -40,23 +39,23 @@ is easy to introduce bugs where properties are not yet synchronized: ```javascript Person.reopen({ - lastNameChanged: function() { + lastNameChanged: Ember.observer('lastName', function() { // The observer depends on lastName and so does fullName. Because observers // are synchronous, when this function is called the value of fullName is // not updated yet so this will log the old value of fullName console.log(this.get('fullName')); - }.observes('lastName') + }) }); ``` -This synchronous behaviour can also lead to observers being fired multiple +This synchronous behavior can also lead to observers being fired multiple times when observing multiple properties: ```javascript Person.reopen({ - partOfNameChanged: function() { + partOfNameChanged: Ember.observer('firstName', 'lastName', function() { // Because both firstName and lastName were set, this observer will fire twice. - }.observes('firstName', 'lastName') + }) }); person.set('firstName', 'John'); @@ -69,15 +68,15 @@ next run loop once all bindings are synchronized: ```javascript Person.reopen({ - partOfNameChanged: function() { + partOfNameChanged: Ember.observer('firstName', 'lastName', function() { Ember.run.once(this, 'processFullName'); - }.observes('firstName', 'lastName'), + }), - processFullName: function() { + processFullName: Ember.observer('fullName', function() { // This will only fire once if you set two properties at the same time, and // will also happen in the next run loop once all properties are synchronized console.log(this.get('fullName')); - }.observes('fullName') + }) }); person.set('firstName', 'John'); @@ -89,8 +88,8 @@ person.set('lastName', 'Smith'); Observers never fire until after the initialization of an object is complete. If you need an observer to fire as part of the initialization process, you -cannot rely on the side effect of set. Instead, specify that the observer -should also run after init by using `.on('init')`: +cannot rely on the side effect of `set`. Instead, specify that the observer +should also run after `init` by using `Ember.on()`: ```javascript Person = Ember.Object.extend({ @@ -98,9 +97,9 @@ Person = Ember.Object.extend({ this.set('salutation', "Mr/Ms"); }, - salutationDidChange: function() { + salutationDidChange: Ember.on(Ember.observer('salutation', function() { // some side effect of salutation changing - }.observes('salutation').on('init') + }), 'init') }); ``` @@ -118,20 +117,24 @@ observe it so you can update the DOM once the property changes. If you need to observe a computed property but aren't currently retrieving it, just get it in your init method. - ### Without prototype extensions -You can define inline observers by using the `Ember.observer` method if you -are using Ember without prototype extensions: +You may have also seen observes defined using the `.observes()` syntax: ```javascript Person.reopen({ - fullNameChanged: Ember.observer('fullName', function() { + fullNameChanged: function() { // deal with the change - }) + }.observes('fullName') }); ``` +This is only possible because Ember extends the `function` prototype and is no +longer the recommended syntax. + +More information about extending native prototypes is available in the +[disabling prototype extensions guide](../../configuring-ember/disabling-prototype-extensions/). + ### Outside of class definitions You can also add observers to an object outside of a class definition diff --git a/source/routing/query-params.md b/source/routing/query-params.md index b5f44d6b6..c066a8f5f 100644 --- a/source/routing/query-params.md +++ b/source/routing/query-params.md @@ -43,7 +43,7 @@ export default Ember.Controller.extend({ queryParams: ['category'], category: null, - filteredArticles: function() { + filteredArticles: Ember.computed('category', 'model', function() { var category = this.get('category'); var articles = this.get('model'); @@ -52,7 +52,7 @@ export default Ember.Controller.extend({ } else { return articles; } - }.property('category', 'model') + }) }); ``` diff --git a/source/templates/rendering-with-helpers.md b/source/templates/rendering-with-helpers.md index 8e0b3694c..ff95c9cae 100644 --- a/source/templates/rendering-with-helpers.md +++ b/source/templates/rendering-with-helpers.md @@ -54,9 +54,9 @@ Total Posts: {{postCount}} ```app/controllers/author.js export default Ember.Controller.extend({ - postCount: function() { - return this.get("model.posts.length"); - }.property("model.posts.[]") + postCount: Ember.computed('model.posts.[]', function() { + return this.get('model.posts.length'); + }) }) ``` diff --git a/source/testing/index.md b/source/testing/index.md index 80f904ca3..9ea48431a 100644 --- a/source/testing/index.md +++ b/source/testing/index.md @@ -37,7 +37,7 @@ supported through third-party addons. ### How to Run Your Tests -Run your tests with `ember test` on the command-line. You can re-run your tests on every file-change with `ember test --server`. For more details and options, see [Ember CLI – Testing](http://www.ember-cli.com/#testing) and `ember help test`. +Run your tests with `ember test` on the command-line. You can re-run your tests on every file-change with `ember test --server`. For more details and options, see [Ember CLI – Testing](http://www.ember-cli.com/user-guide/#testing) and `ember help test`. ### Contributing diff --git a/source/testing/testing-components.md b/source/testing/testing-components.md index bde7cfe99..01d0a60c0 100644 --- a/source/testing/testing-components.md +++ b/source/testing/testing-components.md @@ -13,9 +13,9 @@ export default Ember.Component.extend({ layout: layout, classNames: ['pretty-color'], attributeBindings: ['style'], - style: function() { + style: Ember.computed('name', function() { return 'color: ' + this.get('name') + ';'; - }.property('name') + }) }); ``` @@ -214,9 +214,9 @@ export default Ember.Component.extend({ layout: layout, tagName: 'img', attributeBindings: ['width', 'height', 'src'], - src: function() { + src: Ember.computed('width', 'height', function() { return 'http://placekitten.com/' + this.get('width') + '/' + this.get('height'); - }.property('width', 'height') + }) }); ``` @@ -232,9 +232,9 @@ export default Ember.Component.extend({ layout: layout, tagName: 'img', attributeBindings: ['width', 'height', 'src'], - src: function() { + src: Ember.computed('width', 'height', function() { return 'http://placekitten.com/' + this.get('width') + '/' + this.get('height'); - }.property('width', 'height') + }) }); ``` diff --git a/source/testing/unit-testing-basics.md b/source/testing/unit-testing-basics.md index da8e7aeb6..bc5209515 100644 --- a/source/testing/unit-testing-basics.md +++ b/source/testing/unit-testing-basics.md @@ -18,9 +18,9 @@ based on a `foo` property. export default Ember.Object.extend({ foo: 'bar', - computedFoo: function() { + computedFoo: Ember.computed('foo', function() { return 'computed ' + this.get('foo'); - }.property('foo') + }) }); ``` @@ -60,8 +60,8 @@ export default Ember.Object.extend({ }); ``` -To test it, we create an instance of our class `SomeThing` as defined above, -call the `testMethod` method and assert that the internal state is correct as a +To test it, we create an instance of our class `SomeThing` as defined above, +call the `testMethod` method and assert that the internal state is correct as a result of the method call. ```tests/unit/models/some-thing-test.js @@ -114,9 +114,9 @@ Suppose we have an object that has a property and a method observing that proper export default Ember.Object.extend({ foo: 'bar', other: 'no', - doSomething: function(){ + doSomething: Ember.observer('foo', function(){ this.set('other', 'yes'); - }.observes('foo') + }) }); ``` @@ -134,4 +134,3 @@ test('doSomething observer sets other prop', function() { equal(someThing.get('other'), 'yes'); }); ``` -