Skip to content

Instantly share code, notes, and snippets.

@jamesarosen
Created November 18, 2016 20:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save jamesarosen/34f664b437d9fdc574f3685707825cac to your computer and use it in GitHub Desktop.
Save jamesarosen/34f664b437d9fdc574f3685707825cac to your computer and use it in GitHub Desktop.
passing-deferreds-down
import Ember from 'ember';
export default Ember.Component.extend({
classNames: [ 'delete-blog' ],
sudoDeferred: null,
isDone: false,
isWorking: false,
message: null,
actions: {
submit() {
if (this.get('isDone')) return;
const d = Ember.RSVP.defer();
this.set('isWorking', true);
this.set('sudoDeferred', d);
d.promise
.then((token) => {
this.set('isDone', true);
this.set('message', 'Deleted');
})
.catch((message) => {
this.set('message', message);
})
.finally(() => {
this.set('isWorking', false);
});
}
}
});
import Ember from 'ember';
export default Ember.Component.extend({
password: null,
deferred: Ember.computed({
get() { return null; },
set(_, deferred) {
if (deferred) {
this.checkSudoAccess()
.then(deferred.resolve, deferred.reject);
}
return deferred;
}
}),
checkSudoAccess() {
return new Ember.RSVP.Promise(function(resolve) {
Ember.run.later(resolve, 2500);
})
.then(() => {
if (this.get('password') === 'p@ssw0rd') {
return '$ud0t0k3n';
}
return Ember.RSVP.reject('Password incorrect');
});
}
});
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Ember Twiddle'
});
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
.delete-blog {
border: 1px solid #444;
padding: 1em;
}
<h1>Passing Deferreds Down</h1>
<p>
In this Twiddle, we show how a parent component can wait for a child component to complete some asynchronous action that the parent initiates. In this example, the parent is a <code>component:delete-blog</code>, which requires the user enter "sudo mode" by entering their password into a <code>component:sudo-field</code>. The flow is as follows:
</p>
<ol>
<li>The user submits the form, triggering an action on the parent</li>
<li>The parent creates an RSVP <em>deferred object</em>, which it passes down to the child</li>
<li>The child exchanges the password for a sudo token and resolves the <code>RSPV.Deferred</code> with the token</li>
<li>The parent uses the token to make the <em>delete-blog</em> request</li>
</ol>
{{delete-blog name="Weasels of the World"}}
<p>
We might use this technique for any situation where a <em>parent</em> initiates an asynchronous action that the <em>child</em> is responsible for completing. If the user can cancel the action, we might use a
<a href='http://ember-concurrency.com/#/docs/cancelation' taret='_blank'>cancelable ember-concurrency task</a>
instead of an RSVP deferred object. This is a great interface for a modal-dialog that asks for confirmation for some action.
</p>
<form {{action 'submit' on='submit'}}>
To delete the blog "{{name}}", you must enter your password.
{{sudo-field deferred=sudoDeferred}}
{{#if message}}
<div>{{message}}</div>
{{/if}}
{{#if isWorking}}
⌛️
{{else if isDone}}
{{else}}
<input type='submit' value='Delete' />
{{/if}}
</form>
<label for='sudo-password'>Password:</label>
{{input id='sudo-password' value=password}}
🔒
{
"version": "0.10.6",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.9.0",
"ember-data": "2.9.0",
"ember-template-compiler": "2.9.0",
"ember-testing": "2.9.0"
},
"addons": {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment