diff --git a/packages/@ember/-internals/metal/lib/computed.ts b/packages/@ember/-internals/metal/lib/computed.ts index 750c45d57c3..d2b45df16fe 100644 --- a/packages/@ember/-internals/metal/lib/computed.ts +++ b/packages/@ember/-internals/metal/lib/computed.ts @@ -47,50 +47,140 @@ const DEEP_EACH_REGEX = /\.@each\.[^.]+\./; function noop(): void {} /** - A computed property transforms an object literal with object's accessor function(s) into a property. + `@computed` is a decorator that turns a JavaScript getter and setter into a + computed property, which is a _cached, trackable value_. By default the getter + will only be called once and the result will be cached. You can specify + various properties that your computed property depends on. This will force the + cached result to be cleared if the dependencies are modified, and lazily recomputed the next time something asks for it. + + In the following example we decorate a getter - `fullName` - by calling + `computed` with the property dependencies (`firstName` and `lastName`) as + arguments. The `fullName` getter will be called once (regardless of how many + times it is accessed) as long as its dependencies do not change. Once + `firstName` or `lastName` are updated any future calls to `fullName` will + incorporate the new values, and any watchers of the value such as templates + will be updated: - By default the function backing the computed property will only be called - once and the result will be cached. You can specify various properties - that your computed property depends on. This will force the cached - result to be recomputed if the dependencies are modified. + ```javascript + import { computed, set } from '@ember/object'; + + class Person { + constructor(firstName, lastName) { + set(this, 'firstName', firstName); + set(this, 'lastName', lastName); + } + + @computed('firstName', 'lastName') + get fullName() { + return `${this.firstName} ${this.lastName}`; + } + }); + + let tom = new Person('Tom', 'Dale'); - In the following example we declare a computed property - `fullName` - by calling - `computed` with property dependencies (`firstName` and `lastName`) as leading arguments and getter accessor function. The `fullName` getter function - will be called once (regardless of how many times it is accessed) as long - as its dependencies have not changed. Once `firstName` or `lastName` are updated - any future calls (or anything bound) to `fullName` will incorporate the new - values. + tom.fullName; // 'Tom Dale' + ``` + + You can also provide a setter, which will be used when updating the computed + property. Ember's `set` function must be used to update the property + since it will also notify observers of the property: ```javascript - import EmberObject, { computed } from '@ember/object'; + import { computed, set } from '@ember/object'; - let Person = EmberObject.extend({ - // these will be supplied by `create` - firstName: null, - lastName: null, + class Person { + constructor(firstName, lastName) { + set(this, 'firstName', firstName); + set(this, 'lastName', lastName); + } - fullName: computed('firstName', 'lastName', function() { - let firstName = this.get('firstName'), - lastName = this.get('lastName'); + @computed('firstName', 'lastName') + get fullName() { + return `${this.firstName} ${this.lastName}`; + } - return `${firstName} ${lastName}`; - }) + set fullName(value) { + let [firstName, lastName] = value.split(' '); + + set(this, 'firstName', firstName); + set(this, 'lastName', lastName); + } }); - let tom = Person.create({ - firstName: 'Tom', - lastName: 'Dale' + let person = new Person(); + + set(person, 'fullName', 'Peter Wagenet'); + person.firstName; // 'Peter' + person.lastName; // 'Wagenet' + ``` + + You can also pass a getter function or object with `get` and `set` functions + as the last argument to the computed decorator. This allows you to define + computed property _macros_: + + ```js + import { computed } from '@ember/object'; + + function join(...keys) { + return computed(...keys, function() { + return keys.map(key => this[key]).join(' '); + }); + } + + class Person { + @join('firstName', 'lastName') + fullName; + } + ``` + + Note that when defined this way, getters and setters receive the _key_ of the + property they are decorating as the first argument. Setters receive the value + they are setting to as the second argument instead. Additionally, setters must + _return_ the value that should be cached: + + ```javascript + import { computed, set } from '@ember/object'; + + function fullNameMacro(firstNameKey, lastNameKey) { + @computed(firstNameKey, lastNameKey, { + get() { + return `${this[firstNameKey]} ${this[lastNameKey]}`; + } + + set(key, value) { + let [firstName, lastName] = value.split(' '); + + set(this, firstNameKey, firstName); + set(this, lastNameKey, lastName); + + return value; + } + }); + } + + class Person { + constructor(firstName, lastName) { + set(this, 'firstName', firstName); + set(this, 'lastName', lastName); + } + + @fullNameMacro fullName; }); - tom.get('fullName') // 'Tom Dale' + let person = new Person(); + + set(person, 'fullName', 'Peter Wagenet'); + person.firstName; // 'Peter' + person.lastName; // 'Wagenet' ``` - You can also define what Ember should do when setting a computed property by providing additional function (`set`) in hash argument. - If you try to set a computed property, it will try to invoke setter accessor function with the key and - value you want to set it to as arguments. + Computed properties can also be used in classic classes. To do this, we + provide the getter and setter as the last argument like we would for a macro, + and we assign it to a property on the class definition. This is an _anonymous_ + computed macro: ```javascript - import EmberObject, { computed } from '@ember/object'; + import EmberObject, { computed, set } from '@ember/object'; let Person = EmberObject.extend({ // these will be supplied by `create` @@ -98,57 +188,54 @@ function noop(): void {} lastName: null, fullName: computed('firstName', 'lastName', { - get(key) { - let firstName = this.get('firstName'), - lastName = this.get('lastName'); + get() { + return `${this.firstName} ${this.lastName}`; + } - return firstName + ' ' + lastName; - }, set(key, value) { let [firstName, lastName] = value.split(' '); - this.set('firstName', firstName); - this.set('lastName', lastName); + set(this, 'firstName', firstName); + set(this, 'lastName', lastName); return value; } }) }); - let person = Person.create(); + let tom = Person.create({ + firstName: 'Tom', + lastName: 'Dale' + }); - person.set('fullName', 'Peter Wagenet'); - person.get('firstName'); // 'Peter' - person.get('lastName'); // 'Wagenet' + tom.get('fullName') // 'Tom Dale' ``` - You can overwrite computed property with normal property (no longer computed), that won't change if dependencies change, if you set computed property and it won't have setter accessor function defined. - - You can also mark computed property as `.readOnly()` and block all attempts to set it. + You can overwrite computed property without setters with a normal property (no + longer computed) that won't change if dependencies change. You can also mark + computed property as `.readOnly()` and block all attempts to set it. ```javascript - import EmberObject, { computed } from '@ember/object'; - - let Person = EmberObject.extend({ - // these will be supplied by `create` - firstName: null, - lastName: null, + import { computed, set } from '@ember/object'; - fullName: computed('firstName', 'lastName', { - get(key) { - let firstName = this.get('firstName'); - let lastName = this.get('lastName'); + class Person { + constructor(firstName, lastName) { + set(this, 'firstName', firstName); + set(this, 'lastName', lastName); + } - return firstName + ' ' + lastName; - } - }).readOnly() + @computed('firstName', 'lastName').readOnly() + get fullName() { + return `${this.firstName} ${this.lastName}`; + } }); - let person = Person.create(); + let person = new Person(); person.set('fullName', 'Peter Wagenet'); // Uncaught Error: Cannot set read-only property "fullName" on object: <(...):emberXXX> ``` Additional resources: + - [Decorators RFC](https://github.com/emberjs/rfcs/blob/master/text/0408-decorators.md) - [New CP syntax RFC](https://github.com/emberjs/rfcs/blob/master/text/0011-improved-cp-syntax.md) - [New computed syntax explained in "Ember 1.12 released" ](https://emberjs.com/blog/2015/05/13/ember-1-12-released.html#toc_new-computed-syntax) diff --git a/packages/@ember/canary-features/index.ts b/packages/@ember/canary-features/index.ts index fa0edb8156b..503c779c916 100644 --- a/packages/@ember/canary-features/index.ts +++ b/packages/@ember/canary-features/index.ts @@ -20,7 +20,7 @@ export const DEFAULT_FEATURES = { EMBER_GLIMMER_ANGLE_BRACKET_BUILT_INS: true, EMBER_GLIMMER_ANGLE_BRACKET_NESTED_LOOKUP: true, EMBER_ROUTING_BUILD_ROUTEINFO_METADATA: true, - EMBER_NATIVE_DECORATOR_SUPPORT: null, + EMBER_NATIVE_DECORATOR_SUPPORT: true, }; /** diff --git a/packages/@ember/controller/index.js b/packages/@ember/controller/index.js index a5e3f602888..644b9b35819 100644 --- a/packages/@ember/controller/index.js +++ b/packages/@ember/controller/index.js @@ -25,21 +25,33 @@ const Controller = EmberObject.extend(ControllerMixin); inject as controller } from '@ember/controller'; + export default class PostController extends Controller { + @controller posts; + } + ``` + + Classic Class Example: + + ```app/controllers/post.js + import Controller, { + inject as controller + } from '@ember/controller'; + export default Controller.extend({ posts: controller() }); ``` This example will create a `posts` property on the `post` controller that - looks up the `posts` controller in the container, making it easy to - reference other controllers. + looks up the `posts` controller in the container, making it easy to reference + other controllers. @method inject @static @for @ember/controller @since 1.10.0 - @param {String} name (optional) name of the controller to inject, defaults - to the property's name + @param {String} name (optional) name of the controller to inject, defaults to + the property's name @return {ComputedDecorator} injection decorator instance @public */ diff --git a/packages/@ember/object/index.js b/packages/@ember/object/index.js index e28e8c452aa..f6c720ea8ed 100644 --- a/packages/@ember/object/index.js +++ b/packages/@ember/object/index.js @@ -3,31 +3,109 @@ import { assert } from '@ember/debug'; import { assign } from '@ember/polyfills'; /** - Decorator that turns the target function into an Action - Adds an `actions` object to the target object and creates a passthrough - function that calls the original. This means the function still exists - on the original object, and can be used directly. + Decorator that turns the target function into an Action which can be accessed + directly by reference. ```js - export default class ActionDemoComponent extends Component { + import Component from '@ember/component'; + import { action, set } from '@ember/object'; + + export default class Tooltip extends Component { @action - foo() { - // do something + toggleShowing() { + set(this, 'isShowing', !this.isShowing); } } ``` ```hbs - + + + {{#if isShowing}} +
+ I'm a tooltip! +
+ {{/if}} + ``` + + Decorated actions also interop with the string style template actions: + + ```hbs + + + + {{#if isShowing}} +
+ I'm a tooltip! +
+ {{/if}} ``` It also binds the function directly to the instance, so it can be used in any - context: + context and will correctly refer to the class it came from: + + ```hbs + + + + {{#if isShowing}} +
+ I'm a tooltip! +
+ {{/if}} + ``` + + This can also be used in JavaScript code directly: + + ```js + import Component from '@ember/component'; + import { action, set } from '@ember/object'; + + export default class Tooltip extends Component { + constructor() { + super(...arguments); + + // this.toggleShowing is still bound correctly when added to + // the event listener + document.addEventListener('click', this.toggleShowing); + } + + @action + toggleShowing() { + set(this, 'isShowing', !this.isShowing); + } + } + ``` + + This is considered best practice, since it means that methods will be bound + correctly no matter where they are used. By contrast, the `{{action}}` helper + and modifier can also be used to bind context, but it will be required for + every usage of the method: ```hbs - + + + {{#if isShowing}} +
+ I'm a tooltip! +
+ {{/if}} ``` + + They also do not have equivalents in JavaScript directly, so they cannot be + used for other situations where binding would be useful. + @method action @category EMBER_NATIVE_DECORATOR_SUPPORT @for @ember/object diff --git a/packages/@ember/object/lib/computed/computed_macros.js b/packages/@ember/object/lib/computed/computed_macros.js index f904bfa07fa..d0de2a2ac2d 100644 --- a/packages/@ember/object/lib/computed/computed_macros.js +++ b/packages/@ember/object/lib/computed/computed_macros.js @@ -55,14 +55,37 @@ function generateComputedWithPredicate(name, predicate) { } /** - A computed property that returns true if the value of the dependent + A computed property macro that returns true if the value of the dependent property is null, an empty string, empty array, or empty function. - Example + Example: ```javascript + import { set } from '@ember/object'; + import { empty } from '@ember/object/computed'; + + class ToDoList { + constructor(todos) { + set(this, 'todos', todos); + } + + @empty('todos') isDone; + } + + let todoList = new ToDoList( + ['Unit Test', 'Documentation', 'Release'] + ); + + todoList.isDone; // false + set(todoList, 'todos', []); + todoList.isDone; // true + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { empty } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let ToDoList = EmberObject.extend({ isDone: empty('todos') @@ -72,9 +95,9 @@ function generateComputedWithPredicate(name, predicate) { todos: ['Unit Test', 'Documentation', 'Release'] }); - todoList.get('isDone'); // false - todoList.get('todos').clear(); - todoList.get('isDone'); // true + todoList.isDone; // false + set(todoList, 'todos', []); + todoList.isDone; // true ``` @since 1.6.0 @@ -82,9 +105,9 @@ function generateComputedWithPredicate(name, predicate) { @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which returns true if - the value of the dependent property is null, an empty string, empty array, - or empty function and false if the underlying value is not empty. + @return {ComputedProperty} computed property which returns true if the value + of the dependent property is null, an empty string, empty array, or empty + function and false if the underlying value is not empty. @public */ @@ -95,32 +118,57 @@ export function empty(dependentKey) { } /** - A computed property that returns true if the value of the dependent - property is NOT null, an empty string, empty array, or empty function. + A computed property that returns true if the value of the dependent property + is NOT null, an empty string, empty array, or empty function. - Example + Example: ```javascript + import { set } from '@ember/object'; + import { notEmpty } from '@ember/object/computed'; + + class Hamster { + constructor(backpack) { + set(this, 'backpack', backpack); + } + + @notEmpty('backpack') hasStuff + } + + let hamster = new Hamster( + ['Food', 'Sleeping Bag', 'Tent'] + ); + + hamster.hasStuff; // true + set(hamster, 'backpack', []); + hamster.hasStuff; // false + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { notEmpty } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ hasStuff: notEmpty('backpack') }); - let hamster = Hamster.create({ backpack: ['Food', 'Sleeping Bag', 'Tent'] }); + let hamster = Hamster.create({ + backpack: ['Food', 'Sleeping Bag', 'Tent'] + }); - hamster.get('hasStuff'); // true - hamster.get('backpack').clear(); // [] - hamster.get('hasStuff'); // false + hamster.hasStuff; // true + set(hamster, 'backpack', []); + hamster.hasStuff; // false ``` @method notEmpty @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which returns true if - original value for property is not empty. + @return {ComputedProperty} computed property which returns true if original + value for property is not empty. @public */ export function notEmpty(dependentKey) { @@ -130,15 +178,34 @@ export function notEmpty(dependentKey) { } /** - A computed property that returns true if the value of the dependent - property is null or undefined. This avoids errors from JSLint complaining - about use of ==, which can be technically confusing. + A computed property that returns true if the value of the dependent property + is null or undefined. This avoids errors from JSLint complaining about use of + ==, which can be technically confusing. + + ```javascript + import { set } from '@ember/object'; + import { none } from '@ember/object/computed'; + + class Hamster { + @none('food') isHungry; + } - Example + let hamster = new Hamster(); + + hamster.isHungry; // true + + set(hamster, 'food', 'Banana'); + hamster.isHungry; // false + + set(hamster, 'food', null); + hamster.isHungry; // true + ``` + + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { none } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ isHungry: none('food') @@ -146,19 +213,21 @@ export function notEmpty(dependentKey) { let hamster = Hamster.create(); - hamster.get('isHungry'); // true - hamster.set('food', 'Banana'); - hamster.get('isHungry'); // false - hamster.set('food', null); - hamster.get('isHungry'); // true + hamster.isHungry; // true + + set(hamster, 'food', 'Banana'); + hamster.isHungry; // false + + set(hamster, 'food', null); + hamster.isHungry; // true ``` @method none @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which - returns true if original value for property is null or undefined. + @return {ComputedProperty} computed property which returns true if original + value for property is null or undefined. @public */ export function none(dependentKey) { @@ -168,32 +237,53 @@ export function none(dependentKey) { } /** - A computed property that returns the inverse boolean value - of the original value for the dependent property. + A computed property that returns the inverse boolean value of the original + value for the dependent property. + + Example: + + ```javascript + import { set } from '@ember/object'; + import { not } from '@ember/object/computed'; + + class User { + loggedIn = false; + + @not('loggedIn') isAnonymous; + } + + let user = new User(); + + user.isAnonymous; // true + set(user, 'loggedIn', true); + user.isAnonymous; // false + ``` - Example + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { not } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let User = EmberObject.extend({ + loggedIn: false, + isAnonymous: not('loggedIn') }); - let user = User.create({loggedIn: false}); + let user = User.create(); - user.get('isAnonymous'); // true - user.set('loggedIn', true); - user.get('isAnonymous'); // false + user.isAnonymous; // true + set(user, 'loggedIn', true); + user.isAnonymous; // false ``` @method not @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which returns - inverse of the original value for property + @return {ComputedProperty} computed property which returns inverse of the + original value for property @public */ export function not(dependentKey) { @@ -203,12 +293,40 @@ export function not(dependentKey) { } /** - A computed property that converts the provided dependent property - into a boolean value. + A computed property that converts the provided dependent property into a + boolean value. + + Example: + + ```javascript + import { set } from '@ember/object'; + import { bool } from '@ember/object/computed'; + + + class Hamster { + @bool('numBananas') hasBananas + } + + let hamster = new Hamster(); + + hamster.hasBananas; // false + + set(hamster, 'numBananas', 0); + hamster.hasBananas; // false + + set(hamster, 'numBananas', 1); + hamster.hasBananas; // true + + set(hamster, 'numBananas', null); + hamster.hasBananas; // false + ``` + + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { bool } from '@ember/object/computed'; - import EmberObject from '@ember/object'; + let Hamster = EmberObject.extend({ hasBananas: bool('numBananas') @@ -216,21 +334,24 @@ export function not(dependentKey) { let hamster = Hamster.create(); - hamster.get('hasBananas'); // false - hamster.set('numBananas', 0); - hamster.get('hasBananas'); // false - hamster.set('numBananas', 1); - hamster.get('hasBananas'); // true - hamster.set('numBananas', null); - hamster.get('hasBananas'); // false + hamster.hasBananas; // false + + set(hamster, 'numBananas', 0); + hamster.hasBananas; // false + + set(hamster, 'numBananas', 1); + hamster.hasBananas; // true + + set(hamster, 'numBananas', null); + hamster.hasBananas; // false ``` @method bool @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which converts - to boolean the original value for property + @return {ComputedProperty} computed property which converts to boolean the + original value for property @public */ export function bool(dependentKey) { @@ -240,27 +361,50 @@ export function bool(dependentKey) { } /** - A computed property which matches the original value for the - dependent property against a given RegExp, returning `true` - if the value matches the RegExp and `false` if it does not. + A computed property which matches the original value for the dependent + property against a given RegExp, returning `true` if the value matches the + RegExp and `false` if it does not. - Example + Example: ```javascript + import { set } from '@ember/object'; + import { match } from '@ember/object/computed'; + + class User { + @match('email', /^.+@.+\..+$/) hasValidEmail; + } + + let user = new User(); + + user.hasValidEmail; // false + + set(user, 'email', ''); + user.hasValidEmail; // false + + set(user, 'email', 'ember_hamster@example.com'); + user.hasValidEmail; // true + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { match } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let User = EmberObject.extend({ hasValidEmail: match('email', /^.+@.+\..+$/) }); - let user = User.create({loggedIn: false}); + let user = User.create(); + + user.hasValidEmail; // false - user.get('hasValidEmail'); // false - user.set('email', ''); - user.get('hasValidEmail'); // false - user.set('email', 'ember_hamster@example.com'); - user.get('hasValidEmail'); // true + set(user, 'email', ''); + user.hasValidEmail; // false + + set(user, 'email', 'ember_hamster@example.com'); + user.hasValidEmail; // true ``` @method match @@ -268,8 +412,8 @@ export function bool(dependentKey) { @for @ember/object/computed @param {String} dependentKey @param {RegExp} regexp - @return {ComputedProperty} computed property which match - the original value for property against a given RegExp + @return {ComputedProperty} computed property which match the original value + for property against a given RegExp @public */ export function match(dependentKey, regexp) { @@ -280,14 +424,35 @@ export function match(dependentKey, regexp) { } /** - A computed property that returns true if the provided dependent property - is equal to the given value. + A computed property that returns true if the provided dependent property is + equal to the given value. + + Example: + + ```javascript + import { set } from '@ember/object'; + import { equal } from '@ember/object/computed'; + + class Hamster { + @equal('percentCarrotsEaten', 100) satisfied; + } + + let hamster = new Hamster(); + + hamster.satisfied; // false + + set(hamster, 'percentCarrotsEaten', 100); + hamster.satisfied; // true + + set(hamster, 'percentCarrotsEaten', 50); + hamster.satisfied; // false + ``` - Example + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { equal } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ satisfied: equal('percentCarrotsEaten', 100) @@ -295,11 +460,13 @@ export function match(dependentKey, regexp) { let hamster = Hamster.create(); - hamster.get('satisfied'); // false - hamster.set('percentCarrotsEaten', 100); - hamster.get('satisfied'); // true - hamster.set('percentCarrotsEaten', 50); - hamster.get('satisfied'); // false + hamster.satisfied; // false + + set(hamster, 'percentCarrotsEaten', 100); + hamster.satisfied; // true + + set(hamster, 'percentCarrotsEaten', 50); + hamster.satisfied; // false ``` @method equal @@ -307,8 +474,8 @@ export function match(dependentKey, regexp) { @for @ember/object/computed @param {String} dependentKey @param {String|Number|Object} value - @return {ComputedProperty} computed property which returns true if - the original value for property is equal to the given value. + @return {ComputedProperty} computed property which returns true if the + original value for property is equal to the given value. @public */ export function equal(dependentKey, value) { @@ -318,14 +485,35 @@ export function equal(dependentKey, value) { } /** - A computed property that returns true if the provided dependent property - is greater than the provided value. + A computed property that returns true if the provided dependent property is + greater than the provided value. + + Example: + + ```javascript + import { set } from '@ember/object'; + import { gt } from '@ember/object/computed'; + + class Hamster { + @gt('numBananas', 10) hasTooManyBananas; + } + + let hamster = new Hamster(); - Example + hamster.hasTooManyBananas; // false + + set(hamster, 'numBananas', 3); + hamster.hasTooManyBananas; // false + + set(hamster, 'numBananas', 11); + hamster.hasTooManyBananas; // true + ``` + + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { gt } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ hasTooManyBananas: gt('numBananas', 10) @@ -333,11 +521,13 @@ export function equal(dependentKey, value) { let hamster = Hamster.create(); - hamster.get('hasTooManyBananas'); // false - hamster.set('numBananas', 3); - hamster.get('hasTooManyBananas'); // false - hamster.set('numBananas', 11); - hamster.get('hasTooManyBananas'); // true + hamster.hasTooManyBananas; // false + + set(hamster, 'numBananas', 3); + hamster.hasTooManyBananas; // false + + set(hamster, 'numBananas', 11); + hamster.hasTooManyBananas; // true ``` @method gt @@ -345,8 +535,8 @@ export function equal(dependentKey, value) { @for @ember/object/computed @param {String} dependentKey @param {Number} value - @return {ComputedProperty} computed property which returns true if - the original value for property is greater than given value. + @return {ComputedProperty} computed property which returns true if the + original value for property is greater than given value. @public */ export function gt(dependentKey, value) { @@ -356,14 +546,35 @@ export function gt(dependentKey, value) { } /** - A computed property that returns true if the provided dependent property - is greater than or equal to the provided value. + A computed property that returns true if the provided dependent property is + greater than or equal to the provided value. + + Example: + + ```javascript + import { set } from '@ember/object'; + import { gte } from '@ember/object/computed'; + + class Hamster { + @gte('numBananas', 10) hasTooManyBananas; + } - Example + let hamster = new Hamster(); + + hamster.hasTooManyBananas; // false + + set(hamster, 'numBananas', 3); + hamster.hasTooManyBananas; // false + + set(hamster, 'numBananas', 10); + hamster.hasTooManyBananas; // true + ``` + + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { gte } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ hasTooManyBananas: gte('numBananas', 10) @@ -371,11 +582,13 @@ export function gt(dependentKey, value) { let hamster = Hamster.create(); - hamster.get('hasTooManyBananas'); // false - hamster.set('numBananas', 3); - hamster.get('hasTooManyBananas'); // false - hamster.set('numBananas', 10); - hamster.get('hasTooManyBananas'); // true + hamster.hasTooManyBananas; // false + + set(hamster, 'numBananas', 3); + hamster.hasTooManyBananas; // false + + set(hamster, 'numBananas', 10); + hamster.hasTooManyBananas; // true ``` @method gte @@ -383,8 +596,8 @@ export function gt(dependentKey, value) { @for @ember/object/computed @param {String} dependentKey @param {Number} value - @return {ComputedProperty} computed property which returns true if - the original value for property is greater or equal then given value. + @return {ComputedProperty} computed property which returns true if the + original value for property is greater or equal then given value. @public */ export function gte(dependentKey, value) { @@ -394,14 +607,35 @@ export function gte(dependentKey, value) { } /** - A computed property that returns true if the provided dependent property - is less than the provided value. + A computed property that returns true if the provided dependent property is + less than the provided value. - Example + Example: ```javascript + import { set } from '@ember/object'; + import { lt } from '@ember/object/computed'; + + class Hamster { + @lt('numBananas', 3) needsMoreBananas; + } + + let hamster = new Hamster(); + + hamster.needsMoreBananas; // true + + set(hamster, 'numBananas', 3); + hamster.needsMoreBananas; // false + + set(hamster, 'numBananas', 2); + hamster.needsMoreBananas; // true + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { lt } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ needsMoreBananas: lt('numBananas', 3) @@ -409,11 +643,13 @@ export function gte(dependentKey, value) { let hamster = Hamster.create(); - hamster.get('needsMoreBananas'); // true - hamster.set('numBananas', 3); - hamster.get('needsMoreBananas'); // false - hamster.set('numBananas', 2); - hamster.get('needsMoreBananas'); // true + hamster.needsMoreBananas; // true + + set(hamster, 'numBananas', 3); + hamster.needsMoreBananas; // false + + set(hamster, 'numBananas', 2); + hamster.needsMoreBananas; // true ``` @method lt @@ -421,8 +657,8 @@ export function gte(dependentKey, value) { @for @ember/object/computed @param {String} dependentKey @param {Number} value - @return {ComputedProperty} computed property which returns true if - the original value for property is less then given value. + @return {ComputedProperty} computed property which returns true if the + original value for property is less then given value. @public */ export function lt(dependentKey, value) { @@ -432,14 +668,35 @@ export function lt(dependentKey, value) { } /** - A computed property that returns true if the provided dependent property - is less than or equal to the provided value. + A computed property that returns true if the provided dependent property is + less than or equal to the provided value. - Example + Example: ```javascript + import { set } from '@ember/object'; + import { lte } from '@ember/object/computed'; + + class Hamster { + @lte('numBananas', 3) needsMoreBananas; + } + + let hamster = new Hamster(); + + hamster.needsMoreBananas; // true + + set(hamster, 'numBananas', 5); + hamster.needsMoreBananas; // false + + set(hamster, 'numBananas', 3); + hamster.needsMoreBananas; // true + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { lte } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ needsMoreBananas: lte('numBananas', 3) @@ -447,11 +704,13 @@ export function lt(dependentKey, value) { let hamster = Hamster.create(); - hamster.get('needsMoreBananas'); // true - hamster.set('numBananas', 5); - hamster.get('needsMoreBananas'); // false - hamster.set('numBananas', 3); - hamster.get('needsMoreBananas'); // true + hamster.needsMoreBananas; // true + + set(hamster, 'numBananas', 5); + hamster.needsMoreBananas; // false + + set(hamster, 'numBananas', 3); + hamster.needsMoreBananas; // true ``` @method lte @@ -459,8 +718,8 @@ export function lt(dependentKey, value) { @for @ember/object/computed @param {String} dependentKey @param {Number} value - @return {ComputedProperty} computed property which returns true if - the original value for property is less or equal than given value. + @return {ComputedProperty} computed property which returns true if the + original value for property is less or equal than given value. @public */ export function lte(dependentKey, value) { @@ -470,19 +729,46 @@ export function lte(dependentKey, value) { } /** - A computed property that performs a logical `and` on the - original values for the provided dependent properties. + A computed property that performs a logical `and` on the original values for + the provided dependent properties. - You may pass in more than two properties and even use - property brace expansion. The computed property will - return the first falsy value or last truthy value - just like JavaScript's `&&` operator. + You may pass in more than two properties and even use property brace + expansion. The computed property will return the first falsy value or last + truthy value just like JavaScript's `&&` operator. - Example + Example: ```javascript + import { set } from '@ember/object'; + import { and } from '@ember/object/computed'; + + class Hamster { + @and('hasTent', 'hasBackpack') readyForCamp; + @and('hasWalkingStick', 'hasBackpack') readyForHike; + } + + let tomster = new Hamster(); + + tomster.readyForCamp; // false + + set(tomster, 'hasTent', true); + tomster.readyForCamp; // false + + set(tomster, 'hasBackpack', true); + tomster.readyForCamp; // true + + set(tomster, 'hasBackpack', 'Yes'); + tomster.readyForCamp; // 'Yes' + + set(tomster, 'hasWalkingStick', null); + tomster.readyForHike; // null + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { and } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ readyForCamp: and('hasTent', 'hasBackpack'), @@ -491,116 +777,196 @@ export function lte(dependentKey, value) { let tomster = Hamster.create(); - tomster.get('readyForCamp'); // false - tomster.set('hasTent', true); - tomster.get('readyForCamp'); // false - tomster.set('hasBackpack', true); - tomster.get('readyForCamp'); // true - tomster.set('hasBackpack', 'Yes'); - tomster.get('readyForCamp'); // 'Yes' - tomster.set('hasWalkingStick', null); - tomster.get('readyForHike'); // null + tomster.readyForCamp; // false + + set(tomster, 'hasTent', true); + tomster.readyForCamp; // false + + set(tomster, 'hasBackpack', true); + tomster.readyForCamp; // true + + set(tomster, 'hasBackpack', 'Yes'); + tomster.readyForCamp; // 'Yes' + + set(tomster, 'hasWalkingStick', null); + tomster.readyForHike; // null ``` @method and @static @for @ember/object/computed @param {String} dependentKey* - @return {ComputedProperty} computed property which performs - a logical `and` on the values of all the original values for properties. + @return {ComputedProperty} computed property which performs a logical `and` on + the values of all the original values for properties. @public */ export const and = generateComputedWithPredicate('and', value => value); /** - A computed property which performs a logical `or` on the - original values for the provided dependent properties. + A computed property which performs a logical `or` on the original values for + the provided dependent properties. - You may pass in more than two properties and even use - property brace expansion. The computed property will - return the first truthy value or last falsy value just - like JavaScript's `||` operator. + You may pass in more than two properties and even use property brace + expansion. The computed property will return the first truthy value or last + falsy value just like JavaScript's `||` operator. - Example + Example: ```javascript + import { set } from '@ember/object'; + import { or } from '@ember/object/computed'; + + let Hamster = EmberObject.extend({ + @or('hasJacket', 'hasUmbrella') readyForRain; + @or('hasSunscreen', 'hasUmbrella') readyForBeach; + }); + + let tomster = new Hamster(); + + tomster.readyForRain; // undefined + + set(tomster, 'hasUmbrella', true); + tomster.readyForRain; // true + + set(tomster, 'hasJacket', 'Yes'); + tomster.readyForRain; // 'Yes' + + set(tomster, 'hasSunscreen', 'Check'); + tomster.readyForBeach; // 'Check' + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { or } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ readyForRain: or('hasJacket', 'hasUmbrella'), - readyForBeach: or('{hasSunscreen,hasUmbrella}') + readyForBeach: or('hasSunscreen', 'hasUmbrella') }); let tomster = Hamster.create(); - tomster.get('readyForRain'); // undefined - tomster.set('hasUmbrella', true); - tomster.get('readyForRain'); // true - tomster.set('hasJacket', 'Yes'); - tomster.get('readyForRain'); // 'Yes' - tomster.set('hasSunscreen', 'Check'); - tomster.get('readyForBeach'); // 'Check' + tomster.readyForRain; // undefined + + set(tomster, 'hasUmbrella', true); + tomster.readyForRain; // true + + set(tomster, 'hasJacket', 'Yes'); + tomster.readyForRain; // 'Yes' + + set(tomster, 'hasSunscreen', 'Check'); + tomster.readyForBeach; // 'Check' ``` @method or @static @for @ember/object/computed @param {String} dependentKey* - @return {ComputedProperty} computed property which performs - a logical `or` on the values of all the original values for properties. + @return {ComputedProperty} computed property which performs a logical `or` on + the values of all the original values for properties. @public */ export const or = generateComputedWithPredicate('or', value => !value); /** - Creates a new property that is an alias for another property - on an object. Calls to `get` or `set` this property behave as - though they were called on the original property. + Creates a new property that is an alias for another property on an object. + Calls to `get` or `set` this property behave as though they were called on the + original property. + + Example: + + ```javascript + import { set } from '@ember/object'; + import { alias } from '@ember/object/computed'; + + class Person { + name = 'Alex Matchneer'; + + @alias('name') nomen; + } + + let alex = new Person(); + + alex.nomen; // 'Alex Matchneer' + alex.name; // 'Alex Matchneer' + + set(alex, 'nomen', '@machty'); + alex.name; // '@machty' + ``` + + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { alias } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Person = EmberObject.extend({ name: 'Alex Matchneer', + nomen: alias('name') }); let alex = Person.create(); - alex.get('nomen'); // 'Alex Matchneer' - alex.get('name'); // 'Alex Matchneer' + alex.nomen; // 'Alex Matchneer' + alex.name; // 'Alex Matchneer' - alex.set('nomen', '@machty'); - alex.get('name'); // '@machty' + set(alex, 'nomen', '@machty'); + alex.name; // '@machty' ``` @method alias @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which creates an - alias to the original value for property. + @return {ComputedProperty} computed property which creates an alias to the + original value for property. @public */ /** Where `computed.alias` aliases `get` and `set`, and allows for bidirectional data flow, `computed.oneWay` only provides an aliased `get`. The `set` will - not mutate the upstream property, rather causes the current property to - become the value set. This causes the downstream property to permanently - diverge from the upstream property. + not mutate the upstream property, rather causes the current property to become + the value set. This causes the downstream property to permanently diverge from + the upstream property. + + Example: + + ```javascript + import { set } from '@ember/object'; + import { oneWay }from '@ember/object/computed'; + + class User { + constructor(firstName, lastName) { + set(this, 'firstName', firstName); + set(this, 'lastName', lastName); + } + + @oneWay('firstName') nickName; + } - Example + let teddy = new User('Teddy', 'Zeenny'); + + teddy.nickName; // 'Teddy' + + set(teddy, 'nickName', 'TeddyBear'); + teddy.firstName; // 'Teddy' + teddy.nickName; // 'TeddyBear' + ``` + + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { oneWay } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let User = EmberObject.extend({ firstName: null, lastName: null, + nickName: oneWay('firstName') }); @@ -609,17 +975,19 @@ export const or = generateComputedWithPredicate('or', value => !value); lastName: 'Zeenny' }); - teddy.get('nickName'); // 'Teddy' - teddy.set('nickName', 'TeddyBear'); // 'TeddyBear' - teddy.get('firstName'); // 'Teddy' + teddy.nickName; // 'Teddy' + + set(teddy, 'nickName', 'TeddyBear'); // 'TeddyBear' + teddy.firstName; // 'Teddy' + teddy.nickName; // 'TeddyBear' ``` @method oneWay @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which creates a - one way computed property to the original value for property. + @return {ComputedProperty} computed property which creates a one way computed + property to the original value for property. @public */ export function oneWay(dependentKey) { @@ -627,15 +995,15 @@ export function oneWay(dependentKey) { } /** - This is a more semantically meaningful alias of `computed.oneWay`, - whose name is somewhat ambiguous as to which direction the data flows. + This is a more semantically meaningful alias of `computed.oneWay`, whose name + is somewhat ambiguous as to which direction the data flows. @method reads @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which creates a - one way computed property to the original value for property. + @return {ComputedProperty} computed property which creates a one way computed + property to the original value for property. @public */ @@ -646,15 +1014,41 @@ export function oneWay(dependentKey) { This prevents the reverse flow, and also throws an exception when it occurs. - Example + Example: + + ```javascript + import { set } from '@ember/object'; + import { readOnly } from '@ember/object/computed'; + + class User { + constructor(firstName, lastName) { + set(this, 'firstName', firstName); + set(this, 'lastName', lastName); + } + + @readOnly('firstName') nickName; + }); + + let teddy = new User('Teddy', 'Zeenny'); + + teddy.nickName; // 'Teddy' + + set(teddy, 'nickName', 'TeddyBear'); // throws Exception + // throw new EmberError('Cannot Set: nickName on: ' );` + + teddy.firstName; // 'Teddy' + ``` + + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { readOnly } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let User = EmberObject.extend({ firstName: null, lastName: null, + nickName: readOnly('firstName') }); @@ -663,18 +1057,20 @@ export function oneWay(dependentKey) { lastName: 'Zeenny' }); - teddy.get('nickName'); // 'Teddy' - teddy.set('nickName', 'TeddyBear'); // throws Exception + teddy.nickName; // 'Teddy' + + set(teddy, 'nickName', 'TeddyBear'); // throws Exception // throw new EmberError('Cannot Set: nickName on: ' );` - teddy.get('firstName'); // 'Teddy' + + teddy.firstName; // 'Teddy' ``` @method readOnly @static @for @ember/object/computed @param {String} dependentKey - @return {ComputedProperty} computed property which creates a - one way computed property to the original value for property. + @return {ComputedProperty} computed property which creates a one way computed + property to the original value for property. @since 1.5.0 @public */ @@ -683,14 +1079,35 @@ export function readOnly(dependentKey) { } /** - Creates a new property that is an alias for another property - on an object. Calls to `get` or `set` this property behave as - though they were called on the original property, but also - print a deprecation warning. + Creates a new property that is an alias for another property on an object. + Calls to `get` or `set` this property behave as though they were called on the + original property, but also print a deprecation warning. + + Example: + + ```javascript + import { set } from '@ember/object'; + import { deprecatingAlias } from '@ember/object/computed'; + + class Hamster { + @deprecatingAlias('cavendishCount', { + id: 'hamster.deprecate-banana', + until: '3.0.0' + }) + bananaCount; + } + + let hamster = new Hamster(); + + set(hamster, 'bananaCount', 5); // Prints a deprecation warning. + hamster.cavendishCount; // 5 + ``` + + Classic Class Example: ```javascript + import EmberObject, { set } from '@ember/object'; import { deprecatingAlias } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ bananaCount: deprecatingAlias('cavendishCount', { @@ -701,8 +1118,8 @@ export function readOnly(dependentKey) { let hamster = Hamster.create(); - hamster.set('bananaCount', 5); // Prints a deprecation warning. - hamster.get('cavendishCount'); // 5 + set(hamster, 'bananaCount', 5); // Prints a deprecation warning. + hamster.cavendishCount; // 5 ``` @method deprecatingAlias @@ -710,8 +1127,8 @@ export function readOnly(dependentKey) { @for @ember/object/computed @param {String} dependentKey @param {Object} options Options for `deprecate`. - @return {ComputedProperty} computed property which creates an - alias with a deprecation to the original value for property. + @return {ComputedProperty} computed property which creates an alias with a + deprecation to the original value for property. @since 1.7.0 @public */ diff --git a/packages/@ember/object/lib/computed/reduce_computed_macros.js b/packages/@ember/object/lib/computed/reduce_computed_macros.js index 63aeef51ac7..88c12734e8d 100644 --- a/packages/@ember/object/lib/computed/reduce_computed_macros.js +++ b/packages/@ember/object/lib/computed/reduce_computed_macros.js @@ -54,14 +54,47 @@ function multiArrayMacro(_dependentKeys, callback, name) { } /** - A computed property that returns the sum of the values - in the dependent array. + A computed property that returns the sum of the values in the dependent array. + + Example: + + ```javascript + import { sum } from '@ember/object/computed'; + + class Invoice { + lineItems = [1.00, 2.50, 9.99]; + + @sum('lineItems') total; + } + + let invoice = new Invoice(); + + invoice.total; // 13.49 + ``` + + Classic Class Example: + + ```javascript + import EmberObject from '@ember/object'; + import { sum } from '@ember/object/computed'; + + let Invoice = EmberObject.extend({ + lineItems: [1.00, 2.50, 9.99], + + total: sum('lineItems') + }) + + let invoice = Invoice.create(); + + invoice.total; // 13.49 + ``` @method sum @for @ember/object/computed @static @param {String} dependentKey - @return {ComputedProperty} computes the sum of all values in the dependentKey's array + @return {ComputedProperty} computes the sum of all values in the + dependentKey's array @since 1.4.0 @public */ @@ -70,13 +103,52 @@ export function sum(dependentKey) { } /** - A computed property that calculates the maximum value in the - dependent array. This will return `-Infinity` when the dependent - array is empty. + A computed property that calculates the maximum value in the dependent array. + This will return `-Infinity` when the dependent array is empty. + + Example: ```javascript + import { set } from '@ember/object'; + import { mapBy, max } from '@ember/object/computed'; + + class Person { + children = []; + + @mapBy('children', 'age') childAges; + @max('childAges') maxChildAge; + } + + let lordByron = new Person(); + + lordByron.maxChildAge; // -Infinity + + set(lordByron, 'children', [ + { + name: 'Augusta Ada Byron', + age: 7 + } + ]); + lordByron.maxChildAge; // 7 + + set(lordByron, 'children', [ + ...lordByron.children, + { + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + } + ]); + lordByron.maxChildAge; // 8 + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { mapBy, max } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Person = EmberObject.extend({ childAges: mapBy('children', 'age'), @@ -85,33 +157,40 @@ export function sum(dependentKey) { let lordByron = Person.create({ children: [] }); - lordByron.get('maxChildAge'); // -Infinity - lordByron.get('children').pushObject({ - name: 'Augusta Ada Byron', age: 7 - }); - lordByron.get('maxChildAge'); // 7 - lordByron.get('children').pushObjects([{ - name: 'Allegra Byron', - age: 5 - }, { - name: 'Elizabeth Medora Leigh', - age: 8 - }]); - lordByron.get('maxChildAge'); // 8 + lordByron.maxChildAge; // -Infinity + + set(lordByron, 'children', [ + { + name: 'Augusta Ada Byron', + age: 7 + } + ]); + lordByron.maxChildAge; // 7 + + set(lordByron, 'children', [ + ...lordByron.children, + { + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + } + ]); + lordByron.maxChildAge; // 8 ``` - If the types of the arguments are not numbers, - they will be converted to numbers and the type - of the return value will always be `Number`. - For example, the max of a list of Date objects will be - the highest timestamp as a `Number`. + If the types of the arguments are not numbers, they will be converted to + numbers and the type of the return value will always be `Number`. For example, + the max of a list of Date objects will be the highest timestamp as a `Number`. This behavior is consistent with `Math.max`. @method max @for @ember/object/computed @static @param {String} dependentKey - @return {ComputedProperty} computes the largest value in the dependentKey's array + @return {ComputedProperty} computes the largest value in the dependentKey's + array @public */ export function max(dependentKey) { @@ -119,13 +198,52 @@ export function max(dependentKey) { } /** - A computed property that calculates the minimum value in the - dependent array. This will return `Infinity` when the dependent - array is empty. + A computed property that calculates the minimum value in the dependent array. + This will return `Infinity` when the dependent array is empty. + + Example: ```javascript + import { set } from '@ember/object'; + import { mapBy, min } from '@ember/object/computed'; + + class Person { + children = []; + + @mapBy('children', 'age') childAges; + @min('childAges') minChildAge; + } + + let lordByron = Person.create({ children: [] }); + + lordByron.minChildAge; // Infinity + + set(lordByron, 'children', [ + { + name: 'Augusta Ada Byron', + age: 7 + } + ]); + lordByron.minChildAge; // 7 + + set(lordByron, 'children', [ + ...lordByron.children, + { + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + } + ]); + lordByron.minChildAge; // 5 + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { mapBy, min } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Person = EmberObject.extend({ childAges: mapBy('children', 'age'), @@ -134,26 +252,32 @@ export function max(dependentKey) { let lordByron = Person.create({ children: [] }); - lordByron.get('minChildAge'); // Infinity - lordByron.get('children').pushObject({ - name: 'Augusta Ada Byron', age: 7 - }); - lordByron.get('minChildAge'); // 7 - lordByron.get('children').pushObjects([{ - name: 'Allegra Byron', - age: 5 - }, { - name: 'Elizabeth Medora Leigh', - age: 8 - }]); - lordByron.get('minChildAge'); // 5 + lordByron.minChildAge; // Infinity + + set(lordByron, 'children', [ + { + name: 'Augusta Ada Byron', + age: 7 + } + ]); + lordByron.minChildAge; // 7 + + set(lordByron, 'children', [ + ...lordByron.children, + { + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + } + ]); + lordByron.minChildAge; // 5 ``` - If the types of the arguments are not numbers, - they will be converted to numbers and the type - of the return value will always be `Number`. - For example, the min of a list of Date objects will be - the lowest timestamp as a `Number`. + If the types of the arguments are not numbers, they will be converted to + numbers and the type of the return value will always be `Number`. For example, + the min of a list of Date objects will be the lowest timestamp as a `Number`. This behavior is consistent with `Math.min`. @method min @@ -170,23 +294,45 @@ export function min(dependentKey) { /** Returns an array mapped via the callback - The callback method you provide should have the following signature. - `item` is the current item in the iteration. - `index` is the integer index of the current item in the iteration. + The callback method you provide should have the following signature: + - `item` is the current item in the iteration. + - `index` is the integer index of the current item in the iteration. ```javascript - function(item, index); + function mapCallback(item, index); ``` - Example + Example: ```javascript + import { set } from '@ember/object'; import { map } from '@ember/object/computed'; + + class Hamster { + constructor(chores) { + set(this, 'chores', chores); + } + + @map('chores', function(chore, index) { + return `${chore.toUpperCase()}!`; + }) + excitingChores; + }); + + let hamster = new Hamster(['clean', 'write more unit tests']); + + hamster.excitingChores; // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { map } from '@ember/object/computed'; let Hamster = EmberObject.extend({ excitingChores: map('chores', function(chore, index) { - return chore.toUpperCase() + '!'; + return `${chore.toUpperCase()}!`; }) }); @@ -194,42 +340,47 @@ export function min(dependentKey) { chores: ['clean', 'write more unit tests'] }); - hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] + hamster.excitingChores; // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] ``` You can optionally pass an array of additional dependent keys as the second parameter to the macro, if your map function relies on any external values: ```javascript + import { set } from '@ember/object'; import { map } from '@ember/object/computed'; - import EmberObject from '@ember/object'; - let Hamster = EmberObject.extend({ - excitingChores: map('chores', ['shouldUpperCase'], function(chore, index) { + class Hamster { + shouldUpperCase = false; + + constructor(chores) { + set(this, 'chores', chores); + } + + @map('chores', ['shouldUpperCase'], function(chore, index) { if (this.shouldUpperCase) { - return chore.toUpperCase() + '!'; + return `${chore.toUpperCase()}!`; } else { - return chore + '!'; + return `${chore}!`; } }) - }); + excitingChores; + } - let hamster = Hamster.create({ - shouldUpperCase: false, + let hamster = new Hamster(['clean', 'write more unit tests']); - chores: ['clean', 'write more unit tests'] - }); + hamster.excitingChores; // ['clean!', 'write more unit tests!'] - hamster.get('excitingChores'); // ['clean!', 'write more unit tests!'] - hamster.set('shouldUpperCase', true); - hamster.get('excitingChores'); // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] + set(hamster, 'shouldUpperCase', true); + hamster.excitingChores; // ['CLEAN!', 'WRITE MORE UNIT TESTS!'] ``` @method map @for @ember/object/computed @static @param {String} dependentKey - @param {Array} [additionalDependentKeys] optional array of additional dependent keys + @param {Array} [additionalDependentKeys] optional array of additional + dependent keys @param {Function} callback @return {ComputedProperty} an array mapped via the callback @public @@ -258,9 +409,48 @@ export function map(dependentKey, additionalDependentKeys, callback) { /** Returns an array mapped to the specified key. + Example: + ```javascript + import { set } from '@ember/object'; + import { mapBy } from '@ember/object/computed'; + + class Person { + children = []; + + @mapBy('children', 'age') childAges; + } + + let lordByron = new Person(); + + lordByron.childAges; // [] + + set(lordByron, 'children', [ + { + name: 'Augusta Ada Byron', + age: 7 + } + ]); + lordByron.childAges; // [7] + + set(lordByron, 'children', [ + ...lordByron.children, + { + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + } + ]); + lordByron.childAges; // [7, 5, 8] + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { mapBy } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Person = EmberObject.extend({ childAges: mapBy('children', 'age') @@ -268,17 +458,27 @@ export function map(dependentKey, additionalDependentKeys, callback) { let lordByron = Person.create({ children: [] }); - lordByron.get('childAges'); // [] - lordByron.get('children').pushObject({ name: 'Augusta Ada Byron', age: 7 }); - lordByron.get('childAges'); // [7] - lordByron.get('children').pushObjects([{ - name: 'Allegra Byron', - age: 5 - }, { - name: 'Elizabeth Medora Leigh', - age: 8 - }]); - lordByron.get('childAges'); // [7, 5, 8] + lordByron.childAges; // [] + + set(lordByron, 'children', [ + { + name: 'Augusta Ada Byron', + age: 7 + } + ]); + lordByron.childAges; // [7] + + set(lordByron, 'children', [ + ...lordByron.children, + { + name: 'Allegra Byron', + age: 5 + }, { + name: 'Elizabeth Medora Leigh', + age: 8 + } + ]); + lordByron.childAges; // [7, 5, 8] ``` @method mapBy @@ -306,18 +506,46 @@ export function mapBy(dependentKey, propertyKey) { /** Filters the array by the callback. - The callback method you provide should have the following signature. - `item` is the current item in the iteration. - `index` is the integer index of the current item in the iteration. - `array` is the dependant array itself. + The callback method you provide should have the following signature: + - `item` is the current item in the iteration. + - `index` is the integer index of the current item in the iteration. + - `array` is the dependant array itself. ```javascript - function(item, index, array); + function filterCallback(item, index, array); ``` + Example: + ```javascript + import { set } from '@ember/object'; import { filter } from '@ember/object/computed'; + + class Hamster { + constructor(chores) { + set(this, 'chores', chores); + } + + @filter('chores', function(chore, index, array) { + return !chore.done; + }) + remainingChores; + } + + let hamster = Hamster.create([ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ]); + + hamster.remainingChores; // [{name: 'write more unit tests', done: false}] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { filter } from '@ember/object/computed'; let Hamster = EmberObject.extend({ remainingChores: filter('chores', function(chore, index, array) { @@ -333,32 +561,36 @@ export function mapBy(dependentKey, propertyKey) { ] }); - hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] + hamster.remainingChores; // [{name: 'write more unit tests', done: false}] ``` - You can also use `@each.property` in your dependent key, the callback will still use the underlying array: + You can also use `@each.property` in your dependent key, the callback will + still use the underlying array: ```javascript - import { A } from '@ember/array'; + import { set } from '@ember/object'; import { filter } from '@ember/object/computed'; - import EmberObject from '@ember/object'; - let Hamster = EmberObject.extend({ - remainingChores: filter('chores.@each.done', function(chore, index, array) { - return !chore.get('done'); + class Hamster { + constructor(chores) { + set(this, 'chores', chores); + } + + @filter('chores.@each.done', function(chore, index, array) { + return !chore.done; }) - }); + remainingChores; + } - let hamster = Hamster.create({ - chores: A([ - EmberObject.create({ name: 'cook', done: true }), - EmberObject.create({ name: 'clean', done: true }), - EmberObject.create({ name: 'write more unit tests', done: false }) - ]) - }); - hamster.get('remainingChores'); // [{name: 'write more unit tests', done: false}] - hamster.get('chores').objectAt(2).set('done', true); - hamster.get('remainingChores'); // [] + let hamster = new Hamster([ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ]); + hamster.remainingChores; // [{name: 'write more unit tests', done: false}] + + set(hamster.chores[2], 'done', true); + hamster.remainingChores; // [] ``` Finally, you can optionally pass an array of additional dependent keys as the @@ -367,25 +599,27 @@ export function mapBy(dependentKey, propertyKey) { ```javascript import { filter } from '@ember/object/computed'; - import EmberObject from '@ember/object'; - let Hamster = EmberObject.extend({ - remainingChores: filter('chores', ['doneKey'], function(chore, index, array) { + class Hamster { + constructor(chores) { + set(this, 'chores', chores); + } + + doneKey = 'finished'; + + @filter('chores', ['doneKey'], function(chore, index, array) { return !chore[this.doneKey]; }) - }); + remainingChores; + } - let hamster = Hamster.create({ - doneKey: 'finished' + let hamster = new Hamster([ + { name: 'cook', finished: true }, + { name: 'clean', finished: true }, + { name: 'write more unit tests', finished: false } + ]); - chores: [ - { name: 'cook', finished: true }, - { name: 'clean', finished: true }, - { name: 'write more unit tests', finished: false } - ] - }); - - hamster.get('remainingChores'); // [{name: 'write more unit tests', finished: false}] + hamster.remainingChores; // [{name: 'write more unit tests', finished: false}] ``` @method filter @@ -419,11 +653,36 @@ export function filter(dependentKey, additionalDependentKeys, callback) { } /** - Filters the array by the property and value + Filters the array by the property and value. + + Example: ```javascript + import { set } from '@ember/object'; import { filterBy } from '@ember/object/computed'; + + class Hamster { + constructor(chores) { + set(this, 'chores', chores); + } + + @filterBy('chores', 'done', false) remainingChores; + } + + let hamster = new Hamster([ + { name: 'cook', done: true }, + { name: 'clean', done: true }, + { name: 'write more unit tests', done: false } + ]); + + hamster.remainingChores; // [{ name: 'write more unit tests', done: false }] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { filterBy } from '@ember/object/computed'; let Hamster = EmberObject.extend({ remainingChores: filterBy('chores', 'done', false) @@ -437,7 +696,7 @@ export function filter(dependentKey, additionalDependentKeys, callback) { ] }); - hamster.get('remainingChores'); // [{ name: 'write more unit tests', done: false }] + hamster.remainingChores; // [{ name: 'write more unit tests', done: false }] ``` @method filterBy @@ -466,14 +725,38 @@ export function filterBy(dependentKey, propertyKey, value) { } /** - A computed property which returns a new array with all the unique - elements from one or more dependent arrays. + A computed property which returns a new array with all the unique elements + from one or more dependent arrays. - Example + Example: ```javascript + import { set } from '@ember/object'; import { uniq } from '@ember/object/computed'; + + class Hamster { + constructor(fruits) { + set(this, 'fruits', fruits); + } + + @uniq('fruits') uniqueFruits; + } + + let hamster = new Hamster([ + 'banana', + 'grape', + 'kale', + 'banana' + ]); + + hamster.uniqueFruits; // ['banana', 'grape', 'kale'] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { uniq } from '@ember/object/computed'; let Hamster = EmberObject.extend({ uniqueFruits: uniq('fruits') @@ -488,7 +771,7 @@ export function filterBy(dependentKey, propertyKey, value) { ] }); - hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale'] + hamster.uniqueFruits; // ['banana', 'grape', 'kale'] ``` @method uniq @@ -525,18 +808,43 @@ export function uniq(...args) { } /** - A computed property which returns a new array with all the unique - elements from an array, with uniqueness determined by specific key. + A computed property which returns a new array with all the unique elements + from an array, with uniqueness determined by specific key. - Example + Example: ```javascript + import { set } from '@ember/object'; import { uniqBy } from '@ember/object/computed'; + + class Hamster { + constructor(fruits) { + set(this, 'fruits', fruits); + } + + @uniqBy('fruits', 'id') uniqueFruits; + } + + let hamster = new Hamster([ + { id: 1, 'banana' }, + { id: 2, 'grape' }, + { id: 3, 'peach' }, + { id: 1, 'banana' } + ]); + + hamster.uniqueFruits; // [ { id: 1, 'banana' }, { id: 2, 'grape' }, { id: 3, 'peach' }] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { uniqBy } from '@ember/object/computed'; let Hamster = EmberObject.extend({ uniqueFruits: uniqBy('fruits', 'id') }); + let hamster = Hamster.create({ fruits: [ { id: 1, 'banana' }, @@ -545,7 +853,8 @@ export function uniq(...args) { { id: 1, 'banana' } ] }); - hamster.get('uniqueFruits'); // [ { id: 1, 'banana' }, { id: 2, 'grape' }, { id: 3, 'peach' }] + + hamster.uniqueFruits; // [ { id: 1, 'banana' }, { id: 2, 'grape' }, { id: 3, 'peach' }] ``` @method uniqBy @@ -570,14 +879,47 @@ export function uniqBy(dependentKey, propertyKey) { } /** - A computed property which returns a new array with all the unique - elements from one or more dependent arrays. + A computed property which returns a new array with all the unique elements + from one or more dependent arrays. - Example + Example: ```javascript + import { set } from '@ember/object'; import { union } from '@ember/object/computed'; + + class Hamster { + constructor(fruits, vegetables) { + set(this, 'fruits', fruits); + set(this, 'vegetables', vegetables); + } + + @union('fruits', 'vegetables') ediblePlants; + }); + + let hamster = new, Hamster( + [ + 'banana', + 'grape', + 'kale', + 'banana', + 'tomato' + ], + [ + 'tomato', + 'carrot', + 'lettuce' + ] + ); + + hamster.uniqueFruits; // ['banana', 'grape', 'kale', 'tomato', 'carrot', 'lettuce'] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { union } from '@ember/object/computed'; let Hamster = EmberObject.extend({ uniqueFruits: union('fruits', 'vegetables') @@ -598,15 +940,15 @@ export function uniqBy(dependentKey, propertyKey) { ] }); - hamster.get('uniqueFruits'); // ['banana', 'grape', 'kale', 'tomato', 'carrot', 'lettuce'] + hamster.uniqueFruits; // ['banana', 'grape', 'kale', 'tomato', 'carrot', 'lettuce'] ``` @method union @for @ember/object/computed @static @param {String} propertyKey* - @return {ComputedProperty} computes a new array with all the - unique elements from one or more dependent arrays. + @return {ComputedProperty} computes a new array with all the unique elements + from one or more dependent arrays. @public */ export let union = uniq; @@ -615,28 +957,53 @@ export let union = uniq; A computed property which returns a new array with all the elements two or more dependent arrays have in common. - Example + Example: ```javascript + import { set } from '@ember/object'; import { intersect } from '@ember/object/computed'; + + class FriendGroups { + constructor(adaFriends, charlesFriends) { + set(this, 'adaFriends', adaFriends); + set(this, 'charlesFriends', charlesFriends); + } + + @intersect('adaFriends', 'charlesFriends') friendsInCommon; + } + + let groups = new FriendGroups( + ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], + ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'] + ); + + groups.friendsInCommon; // ['William King', 'Mary Somerville'] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { intersect } from '@ember/object/computed'; - let obj = EmberObject.extend({ + let FriendGroups = EmberObject.extend({ friendsInCommon: intersect('adaFriends', 'charlesFriends') - }).create({ + }); + + let groups = FriendGroups.create({ adaFriends: ['Charles Babbage', 'John Hobhouse', 'William King', 'Mary Somerville'], charlesFriends: ['William King', 'Mary Somerville', 'Ada Lovelace', 'George Peacock'] }); - obj.get('friendsInCommon'); // ['William King', 'Mary Somerville'] + groups.friendsInCommon; // ['William King', 'Mary Somerville'] ``` @method intersect @for @ember/object/computed @static @param {String} propertyKey* - @return {ComputedProperty} computes a new array with all the - duplicated elements from the dependent arrays + @return {ComputedProperty} computes a new array with all the duplicated + elements from the dependent arrays @public */ export function intersect(...args) { @@ -674,29 +1041,62 @@ export function intersect(...args) { } /** - A computed property which returns a new array with all the - properties from the first dependent array that are not in the second - dependent array. + A computed property which returns a new array with all the properties from the + first dependent array that are not in the second dependent array. - Example + Example: ```javascript + import { set } from '@ember/object'; import { setDiff } from '@ember/object/computed'; + + class Hamster { + constructor(likes, fruits) { + set(this, 'likes', likes); + set(this, 'fruits', fruits); + } + + @setDiff('likes', 'fruits') wants; + } + + let hamster = new Hamster( + [ + 'banana', + 'grape', + 'kale' + ], + [ + 'grape', + 'kale', + ] + ); + + hamster.wants; // ['banana'] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { setDiff } from '@ember/object/computed'; let Hamster = EmberObject.extend({ - likes: ['banana', 'grape', 'kale'], wants: setDiff('likes', 'fruits') }); let hamster = Hamster.create({ + likes: [ + 'banana', + 'grape', + 'kale' + ], fruits: [ 'grape', 'kale', ] }); - hamster.get('wants'); // ['banana'] + hamster.wants; // ['banana'] ``` @method setDiff @@ -704,9 +1104,8 @@ export function intersect(...args) { @static @param {String} setAProperty @param {String} setBProperty - @return {ComputedProperty} computes a new array with all the - items from the first dependent array that are not in the second - dependent array + @return {ComputedProperty} computes a new array with all the items from the + first dependent array that are not in the second dependent array @public */ export function setDiff(setAProperty, setBProperty) { @@ -732,14 +1131,33 @@ export function setDiff(setAProperty, setBProperty) { } /** - A computed property that returns the array of values - for the provided dependent properties. + A computed property that returns the array of values for the provided + dependent properties. - Example + Example: ```javascript + import { set } from '@ember/object'; + import { collect } from '@ember/object/computed'; + + class Hamster { + @collect('hat', 'shirt') clothes; + } + + let hamster = new Hamster(); + + hamster.clothes; // [null, null] + + set(hamster, 'hat', 'Camp Hat'); + set(hamster, 'shirt', 'Camp Shirt'); + hamster.clothes; // ['Camp Hat', 'Camp Shirt'] + ``` + + Classic Class Example: + + ```javascript + import EmberObject, { set } from '@ember/object'; import { collect } from '@ember/object/computed'; - import EmberObject from '@ember/object'; let Hamster = EmberObject.extend({ clothes: collect('hat', 'shirt') @@ -747,18 +1165,19 @@ export function setDiff(setAProperty, setBProperty) { let hamster = Hamster.create(); - hamster.get('clothes'); // [null, null] - hamster.set('hat', 'Camp Hat'); - hamster.set('shirt', 'Camp Shirt'); - hamster.get('clothes'); // ['Camp Hat', 'Camp Shirt'] + hamster.clothes; // [null, null] + + set(hamster, 'hat', 'Camp Hat'); + set(hamster, 'shirt', 'Camp Shirt'); + hamster.clothes; // ['Camp Hat', 'Camp Shirt'] ``` @method collect @for @ember/object/computed @static @param {String} dependentKey* - @return {ComputedProperty} computed property which maps - values of all passed in properties to an array. + @return {ComputedProperty} computed property which maps values of all passed + in properties to an array. @public */ export function collect(...dependentKeys) { @@ -777,9 +1196,9 @@ export function collect(...dependentKeys) { } /** - A computed property which returns a new array with all the - properties from the first dependent array sorted based on a property - or sort function. The sort macro can be used in two different ways: + A computed property which returns a new array with all the properties from the + first dependent array sorted based on a property or sort function. The sort + macro can be used in two different ways: 1. By providing a sort callback function 2. By providing an array of keys to sort the array @@ -788,7 +1207,7 @@ export function collect(...dependentKeys) { signature: ```javascript - function(itemA, itemB); + function sortCallback(itemA, itemB); ``` - `itemA` the first item to compare. @@ -803,11 +1222,44 @@ export function collect(...dependentKeys) { itemB` or `itemA.get( 'foo' ) - itemB.get( 'foo' )` can be used instead of series of `if`. - Example + Example: ```javascript + import { set } from '@ember/object'; import { sort } from '@ember/object/computed'; + + class ToDoList { + constructor(todos) { + set(this, 'todos', todos); + } + + // using a custom sort function + @sort('todos', function(a, b){ + if (a.priority > b.priority) { + return 1; + } else if (a.priority < b.priority) { + return -1; + } + + return 0; + }) + priorityTodos; + } + + let todoList = new ToDoList([ + { name: 'Unit Test', priority: 2 }, + { name: 'Documentation', priority: 3 }, + { name: 'Release', priority: 1 } + ]); + + todoList.priorityTodos; // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] + ``` + + Classic Class Example: + + ```javascript import EmberObject from '@ember/object'; + import { sort } from '@ember/object/computed'; let ToDoList = EmberObject.extend({ // using a custom sort function @@ -830,7 +1282,7 @@ export function collect(...dependentKeys) { ] }); - todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] + todoList.priorityTodos; // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] ``` You can also optionally pass an array of additional dependent keys as the @@ -838,12 +1290,18 @@ export function collect(...dependentKeys) { could changes: ```js + import EmberObject, { set } from '@ember/object'; import { sort } from '@ember/object/computed'; - import EmberObject from '@ember/object'; - let ToDoList = EmberObject.extend({ + class ToDoList { + sortKey = 'priority'; + + constructor(todos) { + set(this, 'todos', todos); + } + // using a custom sort function - sortedTodos: sort('todos', ['sortKey'] function(a, b){ + @sort('todos', ['sortKey'], function(a, b){ if (a[this.sortKey] > b[this.sortKey]) { return 1; } else if (a[this.sortKey] < b[this.sortKey]) { @@ -852,59 +1310,60 @@ export function collect(...dependentKeys) { return 0; }) + sortedTodos; }); - let todoList = ToDoList.create({ - sortKey: 'priority', - - todos: [ - { name: 'Unit Test', priority: 2 }, - { name: 'Documentation', priority: 3 }, - { name: 'Release', priority: 1 } - ] - }); + let todoList = new ToDoList([ + { name: 'Unit Test', priority: 2 }, + { name: 'Documentation', priority: 3 }, + { name: 'Release', priority: 1 } + ]); - todoList.get('priorityTodos'); // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] + todoList.priorityTodos; // [{ name:'Release', priority:1 }, { name:'Unit Test', priority:2 }, { name:'Documentation', priority:3 }] ``` In the second form, you should provide the key of the array of sort values as the second parameter: ```javascript + import { set } from '@ember/object'; import { sort } from '@ember/object/computed'; - import EmberObject from '@ember/object'; - let ToDoList = EmberObject.extend({ + class ToDoList { + constructor(todos) { + set(this, 'todos', todos); + } + // using standard ascending sort - todosSorting: Object.freeze(['name']), - sortedTodos: sort('todos', 'todosSorting'), + todosSorting = ['name']; + @sort('todos', 'todosSorting') sortedTodos; // using descending sort - todosSortingDesc: Object.freeze(['name:desc']), - sortedTodosDesc: sort('todos', 'todosSortingDesc'), - }); + todosSortingDesc = ['name:desc']; + @sort('todos', 'todosSortingDesc') sortedTodosDesc; + } - let todoList = ToDoList.create({ - todos: [ - { name: 'Unit Test', priority: 2 }, - { name: 'Documentation', priority: 3 }, - { name: 'Release', priority: 1 } - ] - }); + let todoList = new ToDoList([ + { name: 'Unit Test', priority: 2 }, + { name: 'Documentation', priority: 3 }, + { name: 'Release', priority: 1 } + ]); - todoList.get('sortedTodos'); // [{ name:'Documentation', priority:3 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] - todoList.get('sortedTodosDesc'); // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name:'Documentation', priority:3 }] + todoList.sortedTodos; // [{ name:'Documentation', priority:3 }, { name:'Release', priority:1 }, { name:'Unit Test', priority:2 }] + todoList.sortedTodosDesc; // [{ name:'Unit Test', priority:2 }, { name:'Release', priority:1 }, { name:'Documentation', priority:3 }] ``` @method sort @for @ember/object/computed @static @param {String} itemsKey - @param {Array} [additionalDependentKeys] optional array of additional dependent keys - @param {String or Function} sortDefinition a dependent key to an - array of sort properties (add `:desc` to the arrays sort properties to sort descending) or a function to use when sorting - @return {ComputedProperty} computes a new sorted array based - on the sort property array or callback function + @param {Array} [additionalDependentKeys] optional array of additional + dependent keys + @param {String or Function} sortDefinition a dependent key to an array of sort + properties (add `:desc` to the arrays sort properties to sort descending) or a + function to use when sorting + @return {ComputedProperty} computes a new sorted array based on the sort + property array or callback function @public */ export function sort(itemsKey, additionalDependentKeys, sortDefinition) { diff --git a/packages/@ember/service/index.js b/packages/@ember/service/index.js index d68a67dabdf..665e0c41514 100644 --- a/packages/@ember/service/index.js +++ b/packages/@ember/service/index.js @@ -7,8 +7,8 @@ import { inject as metalInject } from '@ember/-internals/metal'; */ /** - Creates a property that lazily looks up a service in the container. There - are no restrictions as to what objects a service can be injected into. + Creates a property that lazily looks up a service in the container. There are + no restrictions as to what objects a service can be injected into. Example: @@ -16,6 +16,21 @@ import { inject as metalInject } from '@ember/-internals/metal'; import Route from '@ember/routing/route'; import { inject as service } from '@ember/service'; + export default class ApplicationRoute extends Route { + @service('auth') authManager; + + model() { + return this.authManager.findCurrentUser(); + } + } + ``` + + Classic Class Example: + + ```app/routes/application.js + import Route from '@ember/routing/route'; + import { inject as service } from '@ember/service'; + export default Route.extend({ authManager: service('auth'), @@ -26,8 +41,8 @@ import { inject as metalInject } from '@ember/-internals/metal'; ``` This example will create an `authManager` property on the application route - that looks up the `auth` service in the container, making it easily - accessible in the `model` hook. + that looks up the `auth` service in the container, making it easily accessible + in the `model` hook. @method inject @static