Trigger a function once a REST request has completed - ember.js

While setting up the application router, I am requesting some data to the backend:
App.Node = DS.Model.extend({
...
});
App.ApplicationRoute = Ember.Route.extend({
processReply: function ( ) { do some processing here; },
setupController: function (controller, model) {
this.cache = App.Node.find();
}
});
Now, when the result of the find is received from the backend, I would like to do some data processing, by calling this.processReply()
How can I listen to the completion of the find request? I have tried plugging in to the .then method (assuming find returns a promise), but this is blocking my application.
setupController: function (controller, model) {
var _this = this;
this.cache = App.Node.find().then(function(data) {
_this.process();
});
}

setupController is synchronous unlike the model hooks. You can delay setting the content of the controller from the promise's then. So the bindings/computed properties from the controller fire after the data has loaded.
setupController: function(controller, model) {
App.Node.find().then(function(data) {
controller.set('content', data);
// optionally
// controller.process()
});
}

Related

Ember when does controller reloads? (or reset)

I've noticed that if i use the same controller for different routes it does not get reset so i can keep data shared between routes which is really helpful for me.
But i wonder... when does the controller reloads in ember? (runs the init and cleans all of his properties)?
And can i manually tell the controller to reload itself?
Thanks for the help guys :)
The controllers are generally singleton instances (excluding itemController instances), they live the life of the page.
If you need to reset some properties you can do it during setupController of the route in need.
App.FooRoute = Ember.Route.extend({
model: function(){
//return something...
},
setupController: function(controller, model){
this._super(controller, model);
controller.setProperties({foo:'asdf', bar: 'ewaf'});
}
});
or you can define some method on the controller that resets it all, and call it during the setupController. Computed properties are all marked dirty and recalculated automatically when the model behind the controller is swapped out.
App.FooRoute = Ember.Route.extend({
model: function(){
//return something...
},
setupController: function(controller, model){
this._super(controller, model);
controller.reset();
}
});
App.FooController = Ember.ObjectController.extend({
foo: 'asdf',
bar: 'wert',
reset: function(){
this.setProperties({foo:'asdf', bar: 'ewaf'});
}// if you want it to happen on init tack on .on('init') right here
});
on init
App.FooController = Ember.ObjectController.extend({
foo: 'asdf',
bar: 'wert',
reset: function(){
this.setProperties({foo:'asdf', bar: 'ewaf'});
}.on('init')
});

Caching `this.get("store").findAll("post")` result set

this route sends server request on every transition to the post.index. Including page reload, navigation and link-to 'post.index'.
I really need to load all the posts once, when that route is transitioned to the first time. What is the best way to cache the result set?
App.PostIndexRoute = Em.Route.extend({
model: function() {
return this.get("store").findAll("post")
}
});
I am using Ember 1.0 and Ember Data 1.0.beta3
In your application route's model/setupController you can prefetch:
ApplicationRoute = Em.Route.extend({
setupController: function(controller, model){
this._super(controller, model);
this.store.find("post");
}
});
And in your post index route you could do:
App.PostIndexRoute = Em.Route.extend({
model: function() {
return this.store.all("post")
}
});

How can I have a code executed every time index is hit?

How can I have a bit of code executed whenever / route is visited?
I have this now:
App.indexController = Ember.Controller.extend({
showFront: function () {
alert("zzz");
}
});
But I am stuck. How can I make it actually work?
You can use beforeModel and setupController hooks to execute code when a route is loaded.
App.Router.map(function(){
this.resource('posts', { path: '/posts' }, function() {});
});
App.PostsRoute = Ember.Route.extend({
// http://emberjs.com/api/classes/Ember.Route.html#method_beforeModel
beforeModel: function() {
console.log("beforeModel fired");
},
// http://emberjs.com/api/classes/Ember.Route.html#method_setupController
setupController: function(controller, model){
this._super(controller, model);
console.log("setupController fired");
},
model: function(){
// resolve the promise after a short delay
return Ember.RSVP.Promise(function(resolve, reject){
setTimeout(function(){
resolve(true);
}, 2000);
});
}
});
beforeModel will fire, as the name suggests, before the model is loaded and setupController will fire after the model has loaded. The example in the JSBin uses a delayed loading model to demonstrate the difference.
This example shows the hooks being used for App.Post route, but you can use this on App.ApplicationRoute if you want to have code execute when loading the default route.
JSBin example
You first need to define a route, and then call a function on it.
Read how here:
http://emberjs.com/guides/routing/defining-your-routes/

how to handle ember data error

I'm trying to follow the guide here which is just active last 3 months - https://gist.github.com/machty/5723945
So i had my code like this:
App.UsersRoute = Em.Route.extend
beforeModel: (transition) ->
alert('before')
model: ->
App.User.find({}).then (response) ->
# my code here parses response and sets it
self.controllerFor('users').set('content', response.users)
# for some reason i need to at least return an array
[]
events:
error: (error, transition) ->
alert(error.message)
But the error callback under events is never triggerd. I force my server to return a 500 server error.
beforeModel (or afterModel) isn't triggered as well.
Example of how I would do this using the latest builds of Ember and EmberData:
App = Ember.Application.create({});
App.User = DS.Model;
App.IndexRoute = Ember.Route.extend({
beforeModel: function(){
alert('before');
},
model: function() {
this.store.find('user', {}).then(function() {
alert('response');
}, function() {
alert('error');
});
}
});
Live Demo
Errors can be handled in the second (reject) callback of the promise (then).

while deleting record, transition to another route fails

I'm fairly new to ember.js and I'm doing some experiements. I recently hit a bit of a wall when trying to delete records. Here is my editing route (from which I call delete)
App.PostsEditRoute = Ember.Route.extend({
model: function(params){
return App.Post.find(params.id);
},
exit: function() {
this._super();
tx = this.get('currentModel.transaction');
if(tx)
tx.rollback();
},
setupController: function(controller, model){
controller.set('content', model);
},
events: {
save: function(post){
post.one('didUpdate', this, function(){
this.transitionTo('posts.show', post);
});
post.get('transaction').commit();
},
cancel: function(){
this.transitionTo('posts.show', post);
},
destroyPost: function(context) {
var post = context.get('content');
post.deleteRecord();
post.get('store').commit();
this.transitionTo('posts.index');
}
}
});
So I have a link through which I trigger destroyPost. The record is successfully deleted, and I start to transition to the index route, but an error occurs...
Uncaught Error: Attempted to handle event rollback on while in state rootState.deleted.inFlight. Called with undefined
After this, loading the models for the index page stops and I get an empty page. I can provide any additional code required. Here is the index route.
App.PostsIndexRoute = Em.Route.extend({
model: function(){
return App.Post.find();
},
setupController: function(controller, model){
controller.set('content', model);
}
});
I should note that both of these routes load correctly by themselves. It's only in transition that I get failure.
You need to bind to didDelete like you did with didUpdate in save method.
destroyPost: function(context) {
var post = context.get('content');
post.one('didDelete', this, function () {
this.transitionTo('posts.index');
});
post.deleteRecord();
post.get('transaction').commit();
}
Also, your code seems a bit inconsistent: in the save method you're committing a separate transaction, while in destroyPost you are committing the whole store.