Update URL after model is modified - ember.js

I have a route like this "loans/:loan_id", from a link I redirect to this URL and send an unsaved Loan object as model, so the id is null, which results in the url being "loans/null", however I then save the model and it gets an ID from the server, but how can I update the URL so that it shows the new ID instead of null?
Thanks.

I assume you have a LoanNewController or something similar. Then I further assume that you are trying to transition to the new created loan object directly after you have created it, this will show an id of null since the create loan action is async and you have to wait for the loan to be created on the backend before you do the transition, so in order for it to work you could do the following:
App.LoanNewController = Ember.ObjectController.extend({
saveLoan: function() {
...
this.get('store').commit();
},
...
transitionAfterSave: function() {
if(this.get('content.id')) {
this.transitionToRoute('loan', this.get('content'));
}
}.observes(content.id)
The added observer will observe the content.id and when it is set (when the server call has returned) the transitionAfterSave will be invoked and the transition will get the content passed to it with the correct id in place.
This answer is based mainly on assumptions, since you didn't reveal that much code, but you get the point I guess.
Hope it helps.

Related

Asynchronous loading in an Ember Component

I have an autocomplete component within a form. Upon inserting the component, I run this function:
setSearchInput: (->
username = #get 'targetObject.user.username'
#set('searchInput', username)
).on('didInsertElement')
The targetObject in this case is the form, which has access to the content model's associated user. At this point, the user might not yet be loaded. Typically, this would prompt Ember-Data to query the server and return a promise. However, in this case it does not return a promise. It returns undefined. However, it returns the expected result if I force Ember to pause a second like this:
setSearchInput: (->
window.setTimeout =>
username = #get 'targetObject.content.user.username'
#set('searchInput', username)
, 1000
).on('didInsertElement')
I experience something similar if I set a breakpoint on #set('searchInput', username). username will be undefined, but if I run #get 'targetObject.content.user.username' at this point, it will return the expected result.
Any idea what's going on? Ember-Data is still in beta, so perhaps this is a bug? Has anyone else encountered this behavior?
I'm going to assume user is a belongsTo async object here (if not you'll need to show what content is up there, cause I'm having to guess), and I'm going to do it in javascript (sorry, if I do it in coffeescript it will probably confuse you more ;) )
setSearchInput: function(){
var self = this;
this.get('targetObject.user').then(function(user){
self.set('searchInput', user.get('username'));
});
}.on('didInsertElement')
Example: http://emberjs.jsbin.com/OxIDiVU/691/edit

Force ember data store.find to load from server

Is there a nice way to force Ember Data to load the resource from server eaven if it has it already in store ?
I have a simple show user action that do store.find('users',id) the model is loaded only once at first attempt to display a page the second time i go my model is loaded from the store which is normal ember data behaviour i know. However i need to load it each time.
edit:
the only way i found is to do this :
#store.find('user',{id: params.user_id}).then (users)->
users.get('firstObject')
however it forces me to implement a "fake" show action on my index action ...
I think this... http://emberjs.com/api/data/classes/DS.Model.html#method_reload
model.reload()
Good luck
Additionally you can call getById which will return any instance of that record that exists, or null, then call unloadRecord to remove it from the cache. I like Edu's response as well though, then I wouldn't have to worry about the record existing somewhere else. Maybe I'd use getById then reload that way any references that had a reference to the user got updated. (pardon my errant coffeescript, if it's wrong).
user = #store.find('user', params.user_id)
if (user)
#store.unloadRecord(user)
Hot off the presses, thanks to machty:
There's a new method getting added as part of the query params feature going into beta this weekend called Route.refresh()...
/**
Refresh the model on this route and any child routes, firing the
`beforeModel`, `model`, and `afterModel` hooks in a similar fashion
to how routes are entered when transitioning in from other route.
The current route params (e.g. `article_id`) will be passed in
to the respective model hooks, and if a different model is returned,
`setupController` and associated route hooks will re-fire as well.
An example usage of this method is re-querying the server for the
latest information using the same parameters as when the route
was first entered.
Note that this will cause `model` hooks to fire even on routes
that were provided a model object when the route was initially
entered.
#method refresh
#return {Transition} the transition object associated with this
attempted transition
#since 1.4.0
*/
You can do this in the setupController hook, using a promise, and the reload method mentioned by Edu.
setupController: ->
#store.find('myModel', 1).then (myModel) ->
myModel.reload()
If you are sure that records to display will change after a certain action then you can call this.refresh() method in your Route. For example:
ProductsRoute = Ember.Route.extend
model: ->
#store.find 'product',
activated: true
actions:
accept: (product) ->
if not product.get('activated')
product.set 'activated', true
product.save()
.catch (err) ->
console.log err
product.rollback()
.then =>
#refresh()
ignore: (product) ->
if not product.get('ignored')
product.set 'ignored', true
product.save()
.catch (err) ->
console.log err
product.rollback()
.then =>
#refresh()
If actions are called from child route - e.g. products/proposed - models will be reloaded for parent route and also child routes.
I think that what you are looking for is DS.Store#fetchById

Emberjs linkTo doesnot update collection i.e department.find()

Learning emberjs
I am not sure if this is a stackoverflow question or git issue. So I decided to put it on stackoverflow first.
Here is my Jsbin (Open in firefox ..not in chrome as raw.github file is used)
When I click on "<- All Department" in department template which I reached after creating a new department it does navigate back to departments template
but the #each does not display the newly added department name in list.
It does show the newly added department on refreshing the browser on /departments
UPDATE
It seems that the .set() method is working but for some reason the new object created is returning the name and ID as undefined. Might be a bug with ember-model perhaps.
The best solution for the moment would be to have 2 save methods, one on the edit controller as you currently do and then adding a different save method for creating a new department.
App.NewController = Ember.ObjectController.extend({
save:function(){
var newDep = App.Department.create({name: this.get('name')});
newDep.save();
this.get('target').transitionTo('department', this.get('model'));
}
});
Here is a jsbin with the New controller added - http://jsbin.com/EVUlOyo/1/edit
End Update
It looks like when you are creating the record it is not setting the name value correctly on the object.
I changed the following -
newDepartment = self.get('model');
newDepartment.set('name',this.get('name'));
newDepartment.save();
to -
var newDep = App.Department.create({name: this.get('name')});
newDep.save();
Here is an updated jsbin also http://jsbin.com/EkEXInO/1/edit
Hope that helps and works for you.

saving form with associated model

It seams simple, but I'm stuck on this one. I have a single controller, and single view dedicated to order model, which has nested client. I create empty records on setupController:
route:
ShowroomApp.OrdersRoute = Ember.Route.extend
model: ->
ShowroomApp.Order.createRecord()
setupController: (controller,model) ->
model.set("client", ShowroomApp.Client.createRecord() )
controller.set("content", model )
controller:
save: ->
#content.store.commit()
On OrdersController i have save action to commit changes made in the form. It results in two separate POST requests each one for each model, but the association doesn't build itself. Orders model saves first, and client_id is obviously null because client doesn't exists yet. Later goes Client post and saves the client, but Order model doesn't know about it and stays without client.
Is there any solution to that?
Thanks,
J
This is due to an outstanding ember-data issue - RESTAdapter: Allow new parent, child to be saved at once
Check out Tom Dale's Comment for a possible workaround. It involves manually adding support for saving both records at once.
As an alternative, you might consider adding a onCreate callback to the parent record, then creating the child in the callback. If you are ok with having a second commit() this will get the job done.

Creating vs Modifying in backbone.js

This is my first application using backbone and REST API, I'm a bit confused with some specific scenarios when it comes to creating-editing. So if the model exits on server, it will EDIT, if it doesn't it CREATES.
When I pass on a unique identifier in my model, it knows it exits, but if I pass a combination of existing data without a unique identifier it always assumes it should CREATE. I'm not sure if this should be solved on client side or server.
For instance:
var exportationMod = new Backbone.Model({ 'asset': '/api/v1/asset/'+this.assetID+'/', 'export_configuration': '/api/v1/exportconfiguration/'+this.model.get('id')+'/' });
exportationMod.url = '/api/v1/exportation/';
exportationMod.save();
OK so the server is running with django + tastypie. Should this be validated by the client by first making an extra query, on the server (maybe there is a way of setting a combination of unique keys like mysql), or is there another setting I can tweak so it edits instead of creating?
If you pass data to the server without some unique id, how would the server know what to update?
If it makes sense for your situation, you can override isNew() in your model.
var MyModel = Backbone.Model.extend({
idAttribute: 'somethingUnique',
url: '/api/v1/exportation/',
isNew: function(){
// return true if you want create (POST),
// return false if you want update (PUT)
}
});
By default it looks like this (with the above model, this.id would be the idAttribute value above):
// A model is new if it has never been saved to the server, and lacks an id.
isNew: function() {
return this.id == null;
},
If you want to edit something that already exists on the server, you should just fetch it first before editing/saving it. Also, if there is some unique id that is not called 'id' you can override that on the model as well (see above).