Skip to content

Latest commit

 

History

History
263 lines (175 loc) · 6.64 KB

README.md

File metadata and controls

263 lines (175 loc) · 6.64 KB

Ember Async

A collection of components and helpers for handling async data in Ember.

Installation

ember install ember-async

Usage

Async-View Component

The async-view component is a higher-order component providing support for deferred value resolution using promises, rendering different views for the different promise states.

When passed a value, if the value is a promise, a pending view is rendered until the promise settles. If the promise fulfills successfully, then this component yields to its block expression; if the promise is rejected, an error view is displayed. If the value passed is not a promise, it is rendered immediately by yielding to its block expression.

When yielding to the block expression, both the fulfilledValue and state are passed; when yielding to a pending or rejected component, the original value and state are passed (thus allowing the reason to be retrieved from a rejected promise).

Using this component, the fulfilledValue is guaranteed to be the resolved value from the promise, or be undefined, thus allowing components that require an actual model instance (such as ember-form-for when getting a localized string) to work correctly.

Note: This component has been designed for values that implement Ember.PromiseProxyMixin, such as models returned from a store. Regular promises are not yet supported.

Using default configuration

{{#async-view model as |loadedModel|}}
  {{my-form loadedModel}}
{{#/async-view}}

Configuring with parameters

{{#async-view model
    pendingMessage="Fetching..."
    rejectedMessage="Oops! Something went wrong"
    as |loadedModel|}}

  {{my-form loadedModel}}

{{#/async-view}}
{{#async-view model
    pendingComponent=(component "spinner")
    rejectedComponent=(component "error-message")
    as |loadedModel|}}

  {{my-form loadedModel}}

{{#/async-view}}

Configuring with environment

If using async-view throughout an application, it can be convenient to specify configuration information globally. This can be done through the environment under the key async-view within the ember-async section.

Use the component in a template the same as with the default configuration:

{{#async-view model as |loadedModel|}}
  {{my-form loadedModel}}
{{#/async-view}}

Then specify your options in the app configuration:

ENV['ember-async'] = {
  'async-view': {
    'pendingComponent': 'spinner',
    'rejectedMessage': 'Oops! An error occurred'
  }
}

If you specify any parameters in a template, they will override the parameters specified in the configuration.

Positional Parameters

value

The value to resolve.

Named Parameters

pendingClass

The class name to use on the element wrapping the pendingMessage or pendingComponent. Defaults to async-view--pending.

pendingMessage

The message to display while a promise is pending. Ignored if pendingComponent is specified. Defaults to Loading....

pendingComponent

The component to render while a promise is pending. Can be set to either a component instance, or the name of the component. Passed value and state as positional parameters.

rejectedClass

The class name to use on the element wrapping the rejectedMessage or rejectedComponent. Defaults to async-view--rejected.

rejectedMessage

The message to display when a promise is rejected. Ignored if rejectedComponent is specified. If neither rejectedMessage or rejectedComponent are specified, then the message from the reason for the rejection will be displayed.

rejectedComponent

The component to render when a promise is rejected. Can be set to either a component instance, or the name of the component. Passed value and state as positional parameters.

Positional Block Variables

fulfilledValue

If value is a promise, the resolved value of that promise once it is fulfilled; otherwise, if the promise remains pending or was rejected, undefined. If value is not a promise, then returns value.

state

An object representing the state of the promise containing four properties: isPending, isSettled, isFulfilled and isRejected.

Styling

When a promise is pending or rejected, the message or component is wrapped in a div using the class name async-view--pending or async-view--rejected, respectively.

When this component yields to its block expression, it does so without extra DOM elements, so no styling can be applied.

Async Computed Properties

asyncComputed

asyncComputed allows properties that need to be calculated asynchronously to update templates when they resolve. Using asyncComputed also enables to you await on computed properties to get their resolved value.

Use the same syntax with asyncComputed as you would with computed, but pass in an async function:

user: asyncComputed('userId', async function() {
  let data = await this.get('store').findRecord('user', this.get('userId'));

   // transform data

  return data;
})

Or use the get/set syntax with asyncComputed:

user: asyncComputed('userId', {
  async get() {
    let data = await this.get('store').findRecord('user', this.get('userId'));

     // transform data

    return data;
  },
  async set(key, value) {
    let updatedValue = await saveValue(value);

    return updatedValue;
  }
})

asyncGet

If you need to await on nested async computed properties, or regular computed properties that are returning promises (e.g. by returning the result of findRecord), then use asyncGet to await each property in the path to ensure you get the final resolved value.

For instance:

let accounts = await asyncGet(this, 'user.accounts');

is equivalent to:

let user = await get(this, 'user');
let accounts = user ? await get(user, 'accounts') : undefined;

And solves the problem of user not being awaited on when this is done:

let accounts = await get(this, 'user.accounts');

Related Libraries

Provides helpers for handling async data within templates.

A button whose state reflects the state of a promise returned from a closure action, e.g. for updating the text based on the state of saving a form.

Authors

Legal

© 2017 Crunchy Bananas, LLC

CrunchyBananas.com

Licensed under the MIT license