Ember Update model after action - javascript

I have an ember template that loads some JSON data on page load, there are some buttons and when these buttons are clicked I need to make different json calls and update the model.
Everything works fine in this code but the model is not being updated after the action is triggered and the json call is made.
How can I fix it?
App.DatRoute = Ember.Route.extend({
model: function(parms){
return Em.RSVP.hash({
datam : Ember.$.getJSON('URL')
});
},
afterModel: function(){
$(document).attr('title', 'Title');
},
renderTemplate: function() {
this.render();
this.render('fter', { into: 'outlet', outlet: 'fter' });
},
actions :{
action: function(){
return Em.RSVP.hash({
datam : Ember.$.getJSON('URL', {data})
});
}
}
});
Thanks

Because you're not doing anything that updates the model. Ember does nothing with the return value from an action, be it a promise or otherwise. You need to put the action on the controller and set the model with the data coming back from the ajax call:
action: function() {
var self = this;
Ember.$.getJSON('URL', {data})
.then(function(result) {
self.set('model', result);
});
}
or my style, entirely equivalent
action: function() {
var set = this.set.bind(this, 'model');
Ember.$.getJSON('URL', {data}).then(set);
}

Related

Emulating socket event how do I update the relevant view with received model data?

I am trying to emulate multiple socket responses listening for each response in my view and updating the model, right now however I am managing to update each view with the same data. Can anyone advise what I would need to have in place in order to update the view relating to the data, right now I'm very confused about how this all works like should there be unique data in the response, should I check this in the view or the model etc?
Sample JS
function outputData(id, name) {
return {
id: id,
name: name
}
};
var View = Backbone.View.extend({
className: 'view',
template: Handlebars.compile( $('.tmpl-view').html() ),
initialize: function() {
this.listenTo(Backbone.Events, 'data:recieved', function(response) {
// Check if this model data is related to this view then set?
this.model.set(response);
this.render();
}.bind(this), this)
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var viewOne = new View({
model: new Backbone.Model()
});
var viewTwo = new View({
model: new Backbone.Model()
});
$('body').append(
viewOne.render().el,
viewTwo.render().el
);
Backbone.Events.trigger('data:recieved', outputData(1, 'Data for viewOne'));
setTimeout(function() {
Backbone.Events.trigger('data:recieved', outputData(2, 'Data for viewTwo'));
}, 400);
JS Fiddle
http://jsfiddle.net/9kf9qvdg/
I would take a slightly different approach. Your view should only listen to changes on the one model it is backed by. This way each view doesn't need to parse every socket message:
initialize: function() {
this.listenTo(this.model, 'change', this.render);
}
Instead you would have separate logic that handles updating your models appropriately when you receive data. This might look like:
function updateData(id, msg) {
var data = outputData(id, msg);
var modelToUpdate = collection.findWhere({id: data.id});
if(modelToUpdate) {
modelToUpdate.set(data);
}
}
Here is a fiddle showing the above in action: http://jsfiddle.net/xwmx64y3/

Backbone model.fetch not setting values

Here is my backbone model constructor
define([], function(){
return Backbone.Model.extend({
urlRoot:'/dummy-api/Instances',
defaults:{
name:null,
read:false,
write:false
},
initialize: function () {
this.fetch();
console.log("after init "+this.get("id")+" name="+this.get("name"));
}
})
});
and at /dummy-api/Instances/1 is have put this
{"id":1,"name":"bangladesh"}
And I have attached this model to a view with this
define(['models/instance.js'], function(Model){
View = Backbone.View.extend({
initialize: function() {
this.model = new Model({
id:1
});
});
return new View();
});
The URL is getting called, and it's content is as above, I can see that in firebug, but "name" isnt getting set.
I know I can provide a parse function, which as I am using sequelize-restful-extended I may need to do, but I'd first like backbone to read and set from a fixed file. The doco is straight forward enough, what I have should work, so am I doing something else bad ?
You're logging the values before the model.fetch has completed.
Set a callback instead to log the values after fetch has successfully completed, and it should work as expected.
define([], function(){
return Backbone.Model.extend({
urlRoot:'/dummy-api/Instances',
defaults:{
name:null,
read:false,
write:false
},
initialize: function () {
this.fetch({
success: function() {
console.log("after init "+this.get("id")+" name="+this.get("name"));
}.bind(this)
});
}
})
});
This is necessary because this.fetch() executes an XMLHttpRequest asynchronously, and continues on to the next line of code while that request is executed by your browser in a separate "thread" (for all intents and purposes).

BackBoneJs donot Delete/Update Model to the server

I have an application that reads/create/update model and save it to the server. But presently I am able to read and save my models from and to the database. But I am unable to delete / update the model from and to the server. currently the views gets deleted of the model but not the model it self
here is the JSFiddle path http://jsfiddle.net/u17xwzLh/1/
$(function() {
Model
var modelContact = Backbone.Model.extend({
defaults: function() {
return {
Id: 0,
Name: "",
Address: ""
};
},
//if i add this idAttribute = "Id" it deletes the value from the server
//but i am unable to create a new model/new entry to the database
clear: function () {
// Deletes the model but the changes are not posted back to the server
this.destroy();
}
});
Collection
// runs fine
var contactCollection = Backbone.Collection.extend({
model: modelContact,
url: 'api/Contact'
});
var contacts = new contactCollection;
ModelView
var contactView = Backbone.View.extend({
tagName: "tr",
events: { // runs fine
"click a.destroy": "clear"
},
template: _.template($("#newContacttemplate").html()), // runs fine
initialize: function() {
this.model.on("change", this.render, this);
this.model.on('destroy', this.remove, this);
},
render: function() { // runs fine
this.$el.html(this.template(this.model.toJSON()));
return this;
},
clear: function () {
this.model.clear();
}
});
MainView
var main = Backbone.View.extend({
el: $("#contactApp"),
events: { // runs fine
"click #btnsave": "CreateNewContact"
},
initialize: function() { // runs fine
this.Nameinput = this.$("#contactname");
this.Addressinput = this.$("#contactaddress");
contacts.on("add", this.AddContact, this);
contacts.on("reset", this.AddContacts, this);
contacts.fetch(); // Note : populates all the database values
},
AddContact: function(contact) { // runs fine
var view = new contactView({ model: contact });
this.$("#tblcontact tbody").append(view.render().el);
},
AddContacts: function() { // runs fine
contacts.each(this.AddContact);
},
CreateNewContact: function(e) { // runs fine
contacts.create({ Name: this.Nameinput.val(), Address: this.Addressinput.val() });
}
});
var m = new main;
});
Right now you have a URL defined on your Backbone.Collection but not on your Backbone.Model, which means you have to do all AJAX work through the Collection. It doesn't have to be that way though: you can add a second URL on yours server-side for Model AJAX operations, or the two could even share a URL (if you set it up appropriately).
The important part, if you want to be able to call this.destroy(); and have it reflected on your server, is that you need:
a URL on your server that can handle requests with the DELETE method (vs. the usual GET or POST methods)
a url property on your Backbone.Model that is set to that server-side URL
Once you have that your call to this.destroy(); will create a DELETE AJAX request, your server will receive that request and know that it should delete the appropriate database record, and then that model will be deleted on both the client- and server-side.

ember.js discard created model if not saving

I have followed the 3 parts of the tutorial here and everything is working fine, with one exception. When I go to the "Add the book" page and then navigate to "List books" without saving, the list of books is extended by an empty item. I suspect that the reason is the following code, where the new model is created before saving and not removed if not saving the form. Any ideas how to fix this?
Embertest.BooksNewRoute = Ember.Route.extend({
model: function() {
return this.get('store').createRecord('book');
},
actions: {
create: function() {
var newBook = this.get('currentModel');
newBook.save();
this.transitionTo('books');
}
}
});
From http://emberjs.com/api/classes/Ember.Route.html#method_deactivate
Add a deactivate function on your route. This is called before exiting this current route. So you can roll back the record you just created in the model like this:
model: function(params) {
return this.get('store').createRecord('book');
},
deactivate: function() {
this.currentModel.rollback();
},
I solved this by attaching an action to destroy the record to the willTransition event as below. Would anyone comment if this is the right approach?
Embertest.BooksNewRoute = Ember.Route.extend({
model: function() {
return this.get('store').createRecord('book');
},
actions: {
willTransition: function() {
if (this.currentModel.get('isNew')) {
this.get('currentModel').deleteRecord();
};
},
create: function() {
var newBook = this.get('currentModel');
newBook.save();
this.transitionTo('books');
}
}
});

Backbone js not populating a model with data using fetch()

I am using Backbone.js and trying to populate my model using fetch(). The problem I am having is that the returned data is not populating my model. I have found a similar question here. The difference is that inside of my success function I am not seeing any data changes nor is a 'change' event being fired.
The code:
Model
window.Company = Backbone.Model.extend({
urlRoot: "/api/company",
defaults:{
"id":null,
"name":"",
"address":"",
"city":"",
"state":"",
"phone":""
},
events: {
'change': 'doChange'
},
doChange: function(event) {
alert('company changed');
}
})
The Router
var AppRouter = Backbone.Router.extend({
routes:{
"":"home",
"company/:id":"companyDetails"
},
initialize:function () {
var user = new User();
this.headerView = new HeaderView({
model: user
});
$('.header').html(this.headerView.el);
console.log("router initialized.");
},
companyDetails: function (id) {
var company = new Company({
id: id
});
company.fetch({
success: function(){
console.log('company.id is ' + company.id);
console.log('company.name is ' + company.name);
console.log('company.address is ' + company.address);
$("#content").html(new CompanyView({
model: company
}).el);
}
});
}
});
JSON
{"address":"555 Main St","name":"Confused Technologies","id":"8dc206cc-1524-4623-a6cd-97c185a76392","state":"CO","city":"Denver","zip":"80206","phone":"5551212"}
The name and address are always undefined. I have to be overlooking something simple???
Edit
Including the view that erroneously left out passing the model to the template.
View
window.CompanyView = Backbone.View.extend({
initialize:function () {
this.render();
console.log('CompanyView initialized');
},
render:function (eventName) {
$(this.el).html(this.template());
return this;
}
})
The attributes are not stored directly on the model. They are stored in an attributes hash, so you would access them through company.attributes, though company.get(attribute) is the way it's usually done. Along the same lines, you would pass company.toJSON() to your template function, as that returns a cloned hash of the model's attributes.
As for your change event not firing, I assume you mean the change: doChange in the model's events hash. Backbone Models do not actually do anything with an events hash. That's for delegating DOM events on Backbone Views. I bet if you put company.on("change", function (model) { console.log(model.toJSON()); }) before your fetch call and removed the success callback, you'd see your model in the console.
Also, I don't think your $("#content").html... line is going to work like you expect. I'd rewrite your router callback like this:
companyDetails: function (id) {
var company = new CompanyView({
el: "#content",
model: new Company({ id: id })
});
// This line would be better in your view's initialize, replacing company with this.
company.listenTo(company.model, "change", company.render);
company.model.fetch();
}
CompanyView#render would typically pass this.model.toJSON() to a template function that returns html, and pass that to this.$el.html(). So something like this.$el.html(this.template(this.model.toJSON()));
OK. The problem with not updating my model was as far as I can tell an async issue. I updated the success callback to include the data parameter like so:
success: function (data) {
$('#content').html(new CompanyView({
model: data
}).el);
}
Note that I am not passing the company object as the model rather the raw returned data. This solved my model problem.
I mentioned in a comment that this started with my underscore template variables `<%= name %>' etc... being empty. I changed my view to this:
window.CompanyView = Backbone.View.extend({
initialize:function () {
this.render();
console.log('CompanyView initialized');
},
render:function (eventName) {
$(this.el).html(this.template(this.model.toJSON()));
return this;
}
})
Those to things got both my model updated and variables propagating to the template.

Categories

Resources