Ember js wait for controller this.get request / rest adapter lag - javascript

I am trying to access my model's content in its respective controller but it initially returns a promise with undefined attributes, then when accessed a second or third time it returns the value.
Could it be there is a delay in retrieving data from the REST adapter?
Also trying to use '.then()' on the request in a controller does not work as I believe it for use only in the route.
App.EquipmentsController = Ember.ArrayController.extend({
getContentForMapping: function() {
console.log(this.get('model').objectAt(1).get('contractor.name'));
//returns undefined first time
}
});
What is strange is that when I access the model's properties from the template view in a loop it returns them straight away.
{{#each equipment in model}}
<p>{{equipment.contractor.name}}</p>
{{/each}}
Below is how I have set up the route. It's grabbing a list of equipment relevant to a specific site:
App.EquipmentsRoute = Ember.Route.extend({
model: function(){
//Get the model for the selected site and grab its equipment list.
return this.modelFor('site').get('equipment');
},
//Set the model we just grabbed above as the model to use in the controller
setupController: function(controller, model) {
controller.set('model', model);
}
});

Changing our API endpoint to support sideloading seems to have fixed the delay we were experiencing when making the this.get('model') request.
There is a small section in the ember guides that covers this: http://emberjs.com/guides/models/the-rest-adapter/

I think the mistake is in your App.EquipmentsRoute's setupController function. Try to set the content property, not the model hook property.
controller.set('content', model);
in
App.EquipmentsRoute = Ember.Route.extend({
[...]
setupController: function(controller, model) {
controller.set('content', model);
}
});

Related

"Rolling back" error states in Ember template

My Ember controller reaches out to a JSONAPI service (using Ember Data) like so:
model: function(params) {
return Ember.RSVP.hash({
data: this.store.query('recipe', params),
...
});
},
The params can contain a filter string that, if malformed, will cause the server to respond with HTTP code 422. I catch this in the same controller like so:
actions: {
error: function(error, transition) {
console.log('Retrieval error: ' + error.message);
this.controller.set('filterValid', false);
}
}
And in my handlebars template, I can then check the {{filterValid}} property of my controller and optionally apply a style to the <input> tag, informing the user of the error.
However: Once the filterValid property has been set to false, I cannot seem to find the right action or hook to then rollback/reset the property to true when the query doesn't fail. Since the above code is in my route, I don't have direct access to the controller in the model function. (Nor, based on the model/controller/template diagrams I've seen, should I.)
I think you maybe looking for the setupController hook. Which receives the resolved model and the controller.
setupController: function(controller, model) {
this._super(controller, model);
controller.set('filterValid', true);
}
I'm not sure if the method is called when an error occurs, (I would guess it's not called), but as you only need to set the flag when things go ok. I think this will work for you.

Model for application route in ember.js

I have the following code where I am trying to set the model for ApplicationRoute but it doesn't seem to work. I have a few doubts regarding the Ember code. Firstly, Can I set a model for application route? Secondly, if the model for the route has fields named count and fileName, do I need to declare these fields in the controller also. It looks like if I do so, the value in the controller takes precedence over the model value. Also can I do something like this.set('total',5) in the setupController even though total isn't defined anywhere.
App.ApplicationRoute=Ember.Route.extend({
model:function(){
console.log('model called');
return {count:3,fileName:'Doc1'};
},
setupController:function(){
console.log(this.get('model').fileName);
this.set('count',this.get('model.count')); //Do I manually need to do this?
this.set('fileName',this.get('model.fileName')); //Do I manually need to do this?
}
});
App.ApplicationController=Ember.Controller.extend({
count:0,//Is this necessary?? Can I directly set the property with declaring it like this
fileName:''
});
You can do:
App.ApplicationController=Ember.Controller.extend({
count: function(){
return this.get('model').get('count');
}.property('model.count')
});
So anytime model.count changes, the propery would get updated automatically.
And yep, you can set the model directly on the route. When you do this.set('total', 5) in the controller, you only set that property on the controller and not the model. In order to update the model, you would need to do:
var model = this.get('model');
model.set('total', 5);
Lastly, your setupController code isn't correct. Here is the sample method found on the Ember docs (located here):
App.SongRoute = Ember.Route.extend({
setupController: function(controller, song) {
controller.set('model', song);
}
});

Ember.js with EmberFire Object - How to use with array attributes?

I read a lot of, still can't solve by myself. I've an Ember Route, with az EmberFire model.
App.NewRoute = Ember.Route.extend({
model: function() {
return EmberFire.Object.create({
ref: window.ref
});
},
setupController: function(controller, model) {
controller.set('model', model);
})
After that for example I've in the controller:
App.NewController = Ember.Controller.extend({
actions: {
save: function() {
this.get('model').set('questions', Ember.A([]));
this.get('model').get('questions').pushObject(Ember.Object.create({title: 'foo'}));
this.get('model').get('questions').get('lastObject').set('title', 'bar');
this.get('model').set('title', 'foobar');
}
}
});
When the save action called only the title change is made on fire base.
Can someone please explain how can I changed the array too?
I would change your model from an EmberFire.Object.create to an EmberFire.Array.create. Instead of having an object with an array as a property. EmberFire is a simple wrapper that bridges ember objects to firebase objects. I don't think it works with nested arrays inside an object yet as I just started working with the library.
If you need a property identified to that array in an object, create a second object EmberFire.Object and add a property questions that references this EmberFire.Array firebase object instead.
So your save action would look more like this:
var array = this.get('model');
array.pushObject(Ember.Object.create({title: 'foo'}));
array.get('lastObject').set('title', 'bar');

Only persist data after submit in Ember.js

I'm using Ember.js and Ember-Data. Users can create and update resources, such as the Organization model. For the most part, the system works as expected. One exception is if a user partially fills out a form and then leaves the page without clicking submit. The partially created resource will persist on the client-side. (It's never submitted to the server and so never exists in the database. If the user reloads the page, these partially created resources disappear.)
My routes are fairly standard:
Whistlr.OrganizationsNewRoute = Ember.Route.extend
model: ->
#store.createRecord('organization')
setupController: (controller, model) ->
controller.set('content', model)
Whistlr.OrganizationEditRoute = Ember.Route.extend
model: (params) ->
#store.find('organization', params.organization_id)
setupController: (controller, model) ->
controller.set('content', #modelFor('organization'))
Perhaps the behavior I've described is also standard? If so, is there a way to prevent it?
You can use the rollback method from DS.Model to revert the local changes.
A good place to use it, is on deactivate method of your route, where you have your form. So when the user exit of the route, the deactivate will be executed, and if have some dirty data, this will be cleaned.
Probally you will need to use the same logic in OrganizationsNewRoute and OrganizationEditRoute, so you can extract to a mixin:
Whistlr.CleanupRecordDataMixin = Ember.Mixin.create({
deactivate: function() {
this.get('controller.content').rollback();
}
});
Whistlr.OrganizationsNewRoute = Ember.Route.extend(Whistlr.CleanupRecordDataMixin, {
// other methods
});
Whistlr.OrganizationEditRoute = Ember.Route.extend(Whistlr.CleanupRecordDataMixin, {
// other methods
});

setupController not being called when using {{linkTo}} or transtionTo("path", model);

Is there any reason why setupController would not get called when using {{linkTo}}? I have two instances in my app where linkTo is being used, and in the second case. It doesn't work. The only difference that I can see is that in the first case linkTo is being used in a loop, and in the second it's not. Below is relevant code for the non-working one:
App.Router.map(function() {
this.resource("search", { path: "/search/:args" });
});
App.SearchCriteria = Ember.Object.extend({ });
App.SearchRoute = Ember.Route.extend({
serialize: function(model, params) {
// .. some code that converts model to a string called args
return {'args': args}
},
model: function(params) {
// convert args, which is query string-formatted, to an object
// and then make a App.SearchCriteria object out of it.
return App.SearchCriteria.create($.deparam(params.args));
},
setupController: function(controller, model) {
controller.set("searchCriteria", model);
}
});
In the search template:
{{view Ember.Checkbox checkedBinding="searchCriteria.music"}} Music
{{#linkTo search searchCriteria}}Search{{/linkTo}}
The last thing I see in the logs is:
Transitioned into 'search'
Normally, I'd see the setupController being called at some point, but it's not happening or some reason. I even tried using the {{action}} method to call a handler and then use transtionTo, but that had the same results.
UPDATE 1: Adding more details
The only difference between the working and non-working cases is that in the working case, the {{linkTo}} is being called from the same template as that of the controller and router (i.e., the linkTo is in the search template and it's invoking the SearchRoute). In the working case, the linkTo is being called on the SearchRoute but from a different template belonging to a different router).
After some Chrome debugging of Ember code, I found out that the router isn't being called is because partitioned.entered is empty. In the working case, it is non-empty.
var aborted = false;
eachHandler(partition.entered, function(handler, context) {
if (aborted) { return; }
if (handler.enter) { handler.enter(); }
setContext(handler, context);
if (handler.setup) {
if (false === handler.setup(context)) {
aborted = true;
}
}
});
UPDATE 2: Root issue found - bug?
I think I understand the root cause of why the handler isn't being triggered, and I think it's because the partitionHandlers(oldHandlers, newHandlers) method doesn't think that the model has changed, thus doesn't fire the handler.
To be specific, this is the relevant part of the view:
{{view Ember.Checkbox checkedBinding="searchCriteria.music"}} Music
{{#linkTo search searchCriteria}}Search{{/linkTo}}
Although the user checks off the checkbox (thus changing the state of searchCriteria), Ember doesn't think that searchCriteria is any different, thus doesn't do anything.
Is this a bug?
I'm not sure what your problem is, but this may help.
setupController is called every time the route is entered. But model hook may not be called every time.
See Ember guide: http://emberjs.com/guides/routing/specifying-a-routes-model/
Note: A route with a dynamic segment will only have its model hook called when it is entered via the URL. If the route is entered through a transition (e.g. when using the link-to Handlebars helper), then a model context is already provided and the hook is not executed. Routes without dynamic segments will always execute the model hook.
Genrally speaking, if you click the link generated by link-to to enter the route, Ember will not call model hook for that route. Instead it passes the model (link-to parameter) to that route.
The philosophy here is since the client already has the model context, Ember think there is no need to get it again from server (that's model hook's job).

Categories