Somewhere in my ember controllers code i loading some data. It looks like this:
models = App.MyModel.find()
It returns <DS.RecordArray:ember763> and send AJAX. I need to add callback on this data loading.
Something like this doesn't work:
models.on 'didLoad', () ->
console.log 'Loaded' #never triggers
How can i solve this problem?
Thanks.
The issue is that when called with no arguments App.MyModel.find() returns a "live array". Semantically a "live array" is always loaded. Behind the scenes, Ember will query your server the first time find() is called on a model.
Instead, use App.MyModel.find({}) to run a findQuery with no params. See this issue for more detail:
https://github.com/emberjs/data/pull/735
Related
I have the following code in my component:
hotelObserver: Ember.computed(function(){
this.get("store").findRecord("hotel", "hotel1").then((hotel)=>{
this.set("hotel", hotel);
});
})
In reality when 2 components are rendered on the same page, only the first promise is resolved. The second promise's then is never called. So I figured that the problem only surfaces when findRecord is called 2 ore more times with the same parameters. Is this the bug or I am doing something wrong?
You could make this call in the init hook of the component, or in the didReceiveAttributes, depending on wether you want to fetch the data on init / on attributes update.
Or, better, why not fetching the data in the model hook of a route ? And passing the data around as a component's argument ?
Given a route it is easy enough to get Ember to navigate to an error route if the model promise rejects. Currently I have the simple method of having an error.hbs and /routes/error.js, and if the model promise errors it loads the error page.
I have a situation where the model resolves fine, but one of its relationships does not. This relationship is used in the routes template e.g.
{{#each model.addresses as |address id|}}
{{address.line1}}
{{/each}}
So myurl.com/api/addresses/1 returns a 500 error. I see this in the console window, but Ember does not automatically transition to the error page. How can I get it to do this for all promises that reject as a result of a template requesting more data?
One solution would be to return RSVP.Promise in route model() which loads all data (also relationships instead of lazy loading them later by template) and rejects if any of asynchronous requests fail.
Ember generates the error pages by it self if im not wrong, if ember depends on an DS.error object for the transition you have to fulfill the requirements in order to get Ember to recognize an valid error, in Ember 2.x the error code MUST be 422 and has to follow jsonapi http://jsonapi.org/format/#errors-processing
I wrote up a long post on using Route error substates here -> https://pixelhandler.com/posts/emberjs-handling-failure-using-route-error-substates
So ultimately, error handling happens as the result of knowing "what broke" and "who owns the fact that it broke". Generally, if X asked for Y and Y fails, its X's job to display the error. In that example, if FooRoute triggers an ajax, and it fails, FooRoute more or less should handle the error.
But when it comes to the template causing fetches, it actually becomes the responsibility of the template.
One thing one can do is, actually bind to the various boolean properties representing the async operation on the PromiseProxy (in your case, model.addresses). The properties are as follows
isPending - ongoing work is happening
isFulfilled - it is done, and succeeded
isRejected - it is done, but failed
isSettled, - it is done (failed or succeeded)
using these flags could be as follows
{{#if model.addresses.isPending}}
loading...
{{else if mode.addresses.isRejected}}
Sorry something went wrong, {{model.addresses.reason.message}}
{{else}}
{{#each model.addresses as |address| }}
...
{{/each}}
{{/if}}
When loading data for a page, I like to ask myself, what data is critical to show? That is, if there are three sections on the page -- say backed by foo, foo.bars, and foo.baz -- are all three sections of highest priority? Or can I let one of them fail and show the other two? Let's assume that without either foo or foo.bars, we show an error page, but foo.baz is optional. In that case, I would write that as
// controller:foo
model(params) {
return this.get('store').find('foo', params.id);
},
afterModel(foo) {
return foo.get('bars'); // block on foo.bars fetch
}
Then I might have a {{foo-baz}} component that renders Loading... at first, then fetches foo.baz in the background and shows the full content later.
Main question:
Is there something like a willSave or beforeSave or beforeCreateRecordor didCreate method for Ember Data RESTAdapter?
Background:
I have a have some data which requires me to make an extra API call, and use the results of that call, before every createRecord.
The problem is, if I try to override createRecord, the DS.Snapshot therein doesn't allow me to change its properties before it gets saved.
Ideally I'd like to make this call before createRecord but I am open to after createRecord as well.
It also needs to be adapter method as far as I can tell, not a model hook, because there is a native object I need access to which I don't want to save on the server. (i.e. DS.Model's didCreate returns the already-stored data from the server)
I don't think you should count on being able to do something before createRecord since we're encouraged to use it directly if we want to push data onto the store. For example if you want to create a record inside of an action you would do:
this.store.createRecord('bank', {
name: this.get('bankForm.name'),
image: this.get('bankForm.image')
});
You can however override the RESTSerializers serialize method that gets called on save to prepare the object to be sent. Then you can change the data to whatever is appropriate to your use case. http://emberjs.com/api/data/classes/DS.RESTSerializer.html#toc_customizing-an-app-wide-serializer
There's of course an equivalent normalize method to override if you're looking at adding something to the object post-save. http://emberjs.com/api/data/classes/DS.RESTSerializer.html#method_normalize
My application's index route gets data from server using Ember.$.getJSON(url) in the route's model hook. The response is then pushed to the store using pushPayload method. When I do foo.get('bars') where foo has many bars (still in the model hook), it results in empty bars. Seen from the server's response and the ember inspector though, the foo's bars actually have some data. So I investigated the foo.get('bars') using chrome's console, and found out the bar records are loaded in its canonicalState property. So my workaround is to use foo.get('bars.canonicalState') instead.
So far its working good, but since it feels hacky and I can't find the canonicalState property in ember's documentation, I would like to know if this is the right way of doing it? and why does this happen?
In your controller, try the following...
...
myBars: Ember.computed.map('foo.bars', function(bar) { return bar; }),
...
Then you should be able to access myBars as a properly constructed array of bar objects.
I am returning some static json from my ajax call for test purpose before the bakend is ready. Nut when I use transitionToRoute from some function I can see the model hook of the route is not always called. I guess it is caching the static json and I see the route rendering properly. But I am also setting some other properties of the controller in the setUpController hook which also doesn't get executed when the model hook is not called.
This variable needs to set whenever I am changing to this route. If setUpController is not the place to set it where should I set it . So it doesn't fail to get set when ember doesn't call model hook as part of caching process.
setupController : function(controller, model ) {
controller.set('isEditing',false);
controller.set('messages', model.messages);
controller.set('params', this.get('params'));
console.log('Set Up controller' );
},
model: function( routeParams) {
this.set('params',routeParams);
// return data omitted code
});
}
So the isEdiding field doesn't get set when model hook is bypassed. One get around solution is set it before transitioning like this
this.controllerFor("messages").set('isEditing',false);
// then do tranisitioning
Is there any better way to acheive the same thing? Like ideally where should this variable setting be done if done properly in Ember ?
Sorry I'm late and this might not be of any use for you. I just wanted to post it over here, if in case it might be of any use for others.
This link helped me, clear my problem.
Approach 1:
We could supply a model for the route. The model will be serialized into the URL using the serialize hook of the route:
var model = self.store.find( 'campaign', { fb_id: fb_id } );
self.transitionToRoute( 'campaign', model);
This will work fine for routing, but the URL might be tampered. For this case, we need to add extra logic to serialize the object passed into the new route and to correct the URL.
Approach 2: If a literal is passed (such as a number or a string), it will be treated as an identifier instead. In this case, the model hook of the route will be triggered:
self.transitionToRoute( 'campaign', fb_id);
This would invoke the model() and would correctly display the required URL on routing. setupController() will be invoked immediately after the model().
2nd one worked fine for me fine. Hope it's useful and answered the above question.