EmberJS saving data - ember.js

My App uses Fixture data (will port to Localstorage later) and I need to implement 'save' method depending on a user click. The user click is an action that maps to the View and from therein the view, it gets transferred to the controller in order to persist info to the model, essentially the template has:
<button {{action 'save' this target='view'}}>Save</button> <!-- note that the 'this' keyword I am sending corresponds to a specific instance of the model that is in a collection, done using an {{#each model}} loop
The view has
actions:{
save:function(card){
// perform some UI activity
this.get('controller').send('save',card); // card representing 'this'
}
}
The controller has:
actions:{
save:function(card){
console.log("controller reached"); // does execute
card.save(); // spits out an error
}
}
Everything works fine however the card.save() method call does not work in the controller. I mean, all I am trying to do is to persist the specific 'card' to my data, but it keeps spitting:
Uncaught TypeError: Object # has no method 'save'
What am I missing here ?
Side notes:
The Controller returns a collection of models
The corresponding'view' for the controller also has the 'edit' partial loaded in it.
So when the user chooses to 'edit' a specific model, it doesn't
transition into a different URL, rather it loads the 'editing' form
within the same URL.
This means that the model in this specific
controller is essentially the collection and I only want to save the
specific model that is being edited.

It appears as if you aren't using any client side record management library (such as ember-data or ember-model). That being said, your instances of App.Card aren't really instances of anything, they are just POJOs and there is no save method defined on a POJO.
It sounds like you'll want to do some research into ember data, or ember model (I'd suggest ember data, http://emberjs.com/guides/models/)
If you don't want to use either, you can just use ajax calls to save data:
save:function(card){
console.log("controller reached"); // does execute
// card; // spits out an error
$.ajax({... , data:$(card), ...});
}
If it's fixture and you have no intention of saving it anywhere, and it's just a dry run, add an ugly alert or log
save:function(card){
console.log("controller reached"); // does execute
console.log('pretend to save ' + card);
alert('pretend to save ' + card);
}

Related

Iterating over DS.hasMany in Ember data

I have a real struggle with Ember.
In my model I have an attribute:
options: DS.hasMany('UserOptions', {async: false})
In a view linked to this model I can easily access this property by e.g.:
{{#each options AS |option|}}
something....
{{/each}}
and that works like a charm.
However when I try to access this model value in controller with:
this.get('model.options')
instead of getting a lovely array of payment options, I get an ember model array of objects, and there's no way I can access the actual data.
Do you guys have any idea how do I access this data in controller and process it?
Thanks!
this.get('model.options') will give you RSVP.Promise, so you need to work with asynchronous code. Use:
this.get('model.options').then(options => {
options.forEach(option => {
// do what you need with option
})
});
Below code solved my case:
#get('model.options').toArray().forEach((item) ->
console.log(item.get('parameter_name')]
)
That's true that console.log(#get('model')) was throwing something strange in console, however when I asked for a specific parameter, it was there!
My problem was that I was trying to print out an entire object instead of a specific value. The values were there, it just didn't print the entire object for a reason.

How do I save all locally created records in ember / ember data?

Currently, the Ember Data filter method has been deprecated. What's the best way to approach saving all new/updated records of a particular type?
You can call save() on a RecordArray so I have been doing:
this.get('store').peekAll('record-type').save() but I'm not sure if there's some better way to go about it.
I would go with:
this.get('store').findAll('users').then((users) => {
users
.filterBy('dirtyType', 'created') // filter for unsaved records
.invoke('save'); // call the save method on each model instance
});
If you return the users object you get an array of promises that you could catch with Ember.RSVP.all(), to listen for when all the users have been saved.

Checking for model update in Computed Property

I'm creating a component for rendering tables. The component is actually a set of nested components and receives a route model and config object, at the top level, then is processed within the component and passed on / iterated over in the next etc.
The final child component receives a model (representing just one row in the table) along with field name that defines which filed to display from the model.
All of this works perfectly and UI updates are bound to the model. The problem that I have is that model updates are not being pushed to the UI. Within my child component I bind to the UI element using the following:
tdVal : function(){
return this.get('data').get(this.get('details').get('field'));
}.property()
tdValUpdated : function(){
this.get('data').set(this.get('details').get('field'),this.get('val'));
}.property('tdVal'),
As you can see there is no computed property literal set for tdVal, which is why model updates are not being pushed to the UI. If I were to give this a literal value such as 'data.status' then status updates to the model are pushed to the UI.
What literal value can I use to compute on any attribute change in the model?
I've tried 'data.isUpdated', 'data.isSaving' etc. I can't use 'data.[]' as the single model, not an array of model.
OK, after much trial and error I think I've found a workaround for this. It's messy and I'm not very happy with it:
//as previous I render the the appropriate value from the model as defined
//by the passed in config object
tdVal : function(){
return this.get('data').get(this.get('details').get('field'));
}.property(),
//then detect UI changes and push to model if required
tdValUpdated : function(){
this.get('data').set(this.get('details').get('field'),this.get('val'));
}.property('tdVal'),
//Then I observe any changes to model isSaving and directly set tdVal with
//the value of the field for the current td
generalUpdateCatch: function() {
this.set('tdVal',this.get('data').get(this.get('details').get('field')));
}.observes('data.isSaving'),
I did try the following instead:
tdVal : function(){
return this.get('data').get(this.get('details').get('field'));
}.observes('data.isSaving'),
But get the error: 'Uncaught TypeError: unsupported content', no idea why? If anybody has a better solution then please post as I very much dislike these workarounds.

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

Ember Data - rollback if navigating away from a form

My application has new / edit forms for a set of entities read from a backend.
When I open such a form, and fill out / edit some fields, then navigate away, the records appear changed in the entity lists, even though I did not commit those changes. Reloading the app (which reloads the data from the backend) fixes the issue, but is not an option.
I've tried doing some transaction rollbacks in the form view's willDestroyElement, but this seems fundamentally wrong since it gets called even after successful form submits (and actually crashes with Attempted to handle event rollback on X while in state rootState.loaded.updated.inFlight).
How would I go about ignoring all unsubmitted form changes (similar to pressing the Cancel button, which performs a transaction rollback), for any use case that involves navigating away from the forms?
Using Ember rc5, Ember Data 0.13.
When exiting the form route, check the state of the record. If its (isNew OR isDirty) and its NOT isSaving, rollback:
App.FormRoute = Ember.Route.extend({
deactivate: function() {
var model = this.controllerFor('form');
if ( (model.get('isNew') || model.get('isDirty')) && (!model.get('isSaving')) ) {
model.rollback();
}
}
});