import { get, setProperties, computed, Mixin } from '@ember/-internals/metal'; import EmberError from '@ember/error'; /** @module @ember/object */ function tap(proxy, promise) { setProperties(proxy, { isFulfilled: false, isRejected: false, }); return promise.then( value => { if (!proxy.isDestroyed && !proxy.isDestroying) { setProperties(proxy, { content: value, isFulfilled: true, }); } return value; }, reason => { if (!proxy.isDestroyed && !proxy.isDestroying) { setProperties(proxy, { reason, isRejected: true, }); } throw reason; }, 'Ember: PromiseProxy' ); } /** A low level mixin making ObjectProxy promise-aware. ```javascript import { resolve } from 'rsvp'; import $ from 'jquery'; import ObjectProxy from '@ember/object/proxy'; import PromiseProxyMixin from '@ember/object/promise-proxy-mixin'; let ObjectPromiseProxy = ObjectProxy.extend(PromiseProxyMixin); let proxy = ObjectPromiseProxy.create({ promise: resolve($.getJSON('/some/remote/data.json')) }); proxy.then(function(json){ // the json }, function(reason) { // the reason why you have no json }); ``` the proxy has bindable attributes which track the promises life cycle ```javascript proxy.get('isPending') //=> true proxy.get('isSettled') //=> false proxy.get('isRejected') //=> false proxy.get('isFulfilled') //=> false ``` When the $.getJSON completes, and the promise is fulfilled with json, the life cycle attributes will update accordingly. Note that $.getJSON doesn't return an ECMA specified promise, it is useful to wrap this with an `RSVP.resolve` so that it behaves as a spec compliant promise. ```javascript proxy.get('isPending') //=> false proxy.get('isSettled') //=> true proxy.get('isRejected') //=> false proxy.get('isFulfilled') //=> true ``` As the proxy is an ObjectProxy, and the json now its content, all the json properties will be available directly from the proxy. ```javascript // Assuming the following json: { firstName: 'Stefan', lastName: 'Penner' } // both properties will accessible on the proxy proxy.get('firstName') //=> 'Stefan' proxy.get('lastName') //=> 'Penner' ``` @class PromiseProxyMixin @public */ export default Mixin.create({ /** If the proxied promise is rejected this will contain the reason provided. @property reason @default null @public */ reason: null, /** Once the proxied promise has settled this will become `false`. @property isPending @default true @public */ isPending: computed('isSettled', function() { return !get(this, 'isSettled'); }).readOnly(), /** Once the proxied promise has settled this will become `true`. @property isSettled @default false @public */ isSettled: computed('isRejected', 'isFulfilled', function() { return get(this, 'isRejected') || get(this, 'isFulfilled'); }).readOnly(), /** Will become `true` if the proxied promise is rejected. @property isRejected @default false @public */ isRejected: false, /** Will become `true` if the proxied promise is fulfilled. @property isFulfilled @default false @public */ isFulfilled: false, /** The promise whose fulfillment value is being proxied by this object. This property must be specified upon creation, and should not be changed once created. Example: ```javascript import ObjectProxy from '@ember/object/proxy'; import PromiseProxyMixin from '@ember/object/promise-proxy-mixin'; ObjectProxy.extend(PromiseProxyMixin).create({ promise: }); ``` @property promise @public */ promise: computed({ get() { throw new EmberError("PromiseProxy's promise must be set"); }, set(key, promise) { return tap(this, promise); }, }), /** An alias to the proxied promise's `then`. See RSVP.Promise.then. @method then @param {Function} callback @return {RSVP.Promise} @public */ then: promiseAlias('then'), /** An alias to the proxied promise's `catch`. See RSVP.Promise.catch. @method catch @param {Function} callback @return {RSVP.Promise} @since 1.3.0 @public */ catch: promiseAlias('catch'), /** An alias to the proxied promise's `finally`. See RSVP.Promise.finally. @method finally @param {Function} callback @return {RSVP.Promise} @since 1.3.0 @public */ finally: promiseAlias('finally'), }); function promiseAlias(name) { return function() { let promise = get(this, 'promise'); return promise[name](...arguments); }; }