backbone boilerplate render view issue - backbone.js

I am using the backbone-boilerplate/backbone-layoutmanager, and I am having issues re-rendering the view after calling place.fetch(). It seems to work fine the first time, but when I do fetch the second time, the "render" method is not getting called anymore.
Any hints would be helpful
thanks
pete
ROUTER
test: function() {
var place = new Place.Model({
place_id: place_id,
});
place.fetch().complete(function(){
app.useLayout("main").setViews({
".place-detail": new Place.Views.Show({
model: place
})
}).render();
});
}
VIEW
initialize: function() {
_.bindAll(this, "render");
this.model.on("change", this.render, this);
}
render: function(manage) {
return manage(this).render();
}

fetch is an async function which accepts an object with a success or error handler which will be called on completion. AFAIK fetch does not support the jQuery method of chaining with a complete handler, so you need to pass it an object with the proper success method set up if you want it called on completion.

Related

Backbone trigger event after custom function possible?

Excuse my backbone i'm not an expert, Must execute function Show absolutely and only after ResetQuestions
ResetQuestions:function () {
//Great Code Here
}),
I tried this:
initialize: function () {
this.on("Show", this.Show, this);
},
ResetQuestions:function () {
//Great Code Here
this.trigger("Show");
}),
But that was unsuccessful, does anyone know how i can accomplish this?
no need of events you can simply call the function from other function
var sampleView = Backbone.View.extend({
initialize: function () {
this.ResetQuestions();
},
Show: function () {
alert('i am at show');
},
ResetQuestions: function () {
// Execute all you code atlast call Show function as below.
this.Show();
}
});
var view = new sampleView();
var sampleView = Backbone.View.extend({
initialize: function(){
this.ResetQuestions().promise().done(function() { // Using promise here.
this.Show();
});
},
Show: function(){
},
ResetQuestions: function(){
// Execute all you code atlast call Show function as below.
}
});
Then initiate your view,
var view = new sampleView();
Hope this works!!
Perhaps you just got confused what runs what and by naming event and method with same name Show. I have created a jsfiddle with your code - http://jsfiddle.net/yuraji/aqymbeyy/ - you call ResetQuestion method, it triggers Show event, and the Show event runs Show method.
EDIT: I have updated the fiddle to demonstrate that you probably have to bind the methods to the instance, I used _.bindAll for that. If you don't do that you may get event as the context (this).
EDIT: Then, if your ResetQuestions runs asynchronous code, like an ajax request to get new questions, you will have to make sure that your Show event is triggered when the request is completed.

Marionette ItemView how to re-render model on change

I'm using Handlebars template engine.
so, I have Model:
Backbone.Model.extend({
urlRoot: Config.urls.getClient,
defaults: {
contract:"",
contractDate:"",
companyTitle:"",
contacts:[],
tariff: new Tariff(),
tariffs: [],
remain:0,
licenses:0,
edo:""
},
initialize:function(){
this.fetch();
}
});
then Marionette ItemView:
Marionette.ItemView.extend({
template : templates.client,
initialize: function () {
this.model.on('change', this.render, this);
},
onRender: function () {
console.log(this.model.toJSON());
}
});
and then I call everything as:
new View({
model : new Model({id:id})
})
and, it's immediately render a view for me and this is cool.
But after the model fetched data it's trigger "change", so I see in console serialised model twice, and I see for first time empty model and then filled one.
But, the view is NOT updated.
How I can fix it?
P.S. I understand, that I can call a render method on fetch done callback. But I also need it for further actions, when user will change model.
In the View, You can use following code
modelEvents: {
'change': 'render'
}
instead of
initialize: function () {
this.model.on('change', this.render, this);
},
onRender: function () {
console.log(this.model.toJSON());
}
Actually, Backbone and Marionette are smart enough to do it.
Problem was in template and data as I found it another question. So, I re-checked everything and got result.

How can I populate the backbone model if I overrode 'fetch'?

I'm building some JS to access Google places JS API using backbone. So far I'm really stuck with the model bindings.
I overrode 'fetch' to be able to use the Google API. The call to Google works just fine.
var Places = Backbone.Collection.extend({
model: Place,
fetch: function(options) {
// SNIPPET //
service = new google.maps.places.PlacesService(map);
service.nearbySearch(request, this.googlePlaceCallback);
// SNIPPET //
},
parse: function(response){
// nerver called
},
googlePlaceCallback: function(results, status) {
// I do something here and is properly called after Google returns a response
}
});
I also defined a very simple View:
var MapView = Backbone.View.extend({
initialize: function() {
this.model = new Places();
this.model.bind("reset", this.render, this);
this.model.fetch();
},
render : function () {
console.log( this.model.toJSON() );
}
});
I can't figure out how to populate the 'model'. Google returns the expected results, but I can set them to the backbone model. I there something I need to do in 'googlePlaceCallback'? I'll probably will need to override 'parse' also since Google results are not quite all interesting.
Assuming that results is a collection of the results you want, you should be able to implement the callback as follows:
googlePlaceCallback: function(results, status) {
this.add(results);
}
Since Places is a backbone Collection, you're just calling the following method in the above code: http://backbonejs.org/#Collection-add
You will also have to get the correct this reference inside the googlePlaceCallback function (you want this to be the Collection). One way to do that is to use Underscores bindAll method ( http://underscorejs.org/#bindAll ), which you can use to make sure all methods in the Backbone class have a this context of the Collection itself. You can do this on initialize as follows:
initialize: function() {
_.bindAll(this);
}
Also, the reason parse is not being called is because you are overriding fetch, and fetch calls parse. If you take a look at the annotated backbone code, you will be able to see the method call: http://backbonejs.org/docs/backbone.html

Backbone.js MVC way to render the view AFTER the data is received back from the server on a fetch?

I wish to read a whole database table to fill a Backbone.js Collection, before updating a View.
I am using fetch and listening to the reset event.
My problem is the reset event fires up before the http request is made to the server.
My question is: how can I render the view AFTER the data is received back from the server on a fetch?
Here is a jsfiddle showing the problem (with a debugger placed at reset):
http://jsfiddle.net/GhaPF/16/
The code:
$(document).ready(function() {
var Item = Backbone.Model.extend({
urlRoot : './items'
});
var ItemList = Backbone.Collection.extend({
model: Item,
url: './items/',
});
var ItemListView = Backbone.View.extend({
el: 'body',
initialize: function(myitemList) {
this.itemlist = myitemList;
this.itemlist.bind('reset', this.debuggThis());
},
debuggThis: function() {
debugger;
},
render: function() {
},
events: {
"keypress #new-item": "createOnEnter"
},
createOnEnter: function(e) {
}
});
$("#new-item").focus();
var itemlist = new ItemList();
var myitemListView = new ItemListView(itemlist);
itemlist.fetch();
});​
The following code works, but it just doesn't feel like proper backbone.js (MVC) code since it would be placed outside of the View definition:
itemlist.fetch().complete(function(){
Maybe the issue is this line:
this.itemlist.bind('reset', this.debuggThis());
Should actually be:
this.itemlist.bind('reset', this.debuggThis);
Your debugThis function was getting run at the time you set up the listener for the 'reset' event - not when the event is triggered. This was telling JavaScript that you wanted debugThis to return a callback function instead of having debugThis "be" the callback function.
Also, orangewarp's comment about passing 'this' as the third parameter is probably relevant too. Sot it would end up as:
this.itemlist.bind('reset', this.debuggThis, this);
That's strange. When you fetch() the reset event should be triggered AFTER your collection is populated. So I'm thinking the phenomena that reset happens before the http request is fired up may not be what you think it is.
Instead of using the complete... you could always just use the success callback option like this:
itemlist.fetch({
success: function() {
// Whatever code you want to run.
itemlist.debuggThis();
}
});
Also, when binding your reset you probably want this:
this.itemlist.bind('reset', this.debuggThis, this);

Backbone.js: retrieving a collection from the server in PHP

I'm having a look at Backbone.js, but I'm stuck. The code until now is as simple as is possible, but I seem not to get it. I use Firebug and this.moments in the render of MomentsView is an object, but all the methods from a collection don't work (ie this.moments.get(1) doesn't work).
The code:
var Moment = Backbone.Model.extend({
});
var Moments = Backbone.Collection.extend({
model: Moment,
url: 'moments',
initialize: function() {
this.fetch();
}
});
var MomentsView = Backbone.View.extend({
el: $('body'),
initialize: function() {
_.bindAll(this, 'render');
this.moments = new Moments();
},
render: function() {
_.each(this.moments, function(moment) {
console.log(moment.get('id'));
});
return this;
}
})
var momentsview = new MomentsView();
momentsview.render();
The (dummy) response from te server:
[{"id":"1","title":"this is the moment","description":"another descr","day":"12"},{"id":"2","title":"this is the mament","description":"onother dascr","day":"14"}]
The object has two models according to the DOM in Firebug, but the methods do not work. Does anybode have an idea how to get the collection to work in the view?
The problem here is that you're fetching the data asynchronously when you initialize the MomentsView view, but you're calling momentsview.render() synchronously, right away. The data you're expecting hasn't come back from the server yet, so you'll run into problems. I believe this will work if you call render in a callback to be executed once fetch() is complete.
Also, I don't think you can call _.each(this.moments) - to iterate over a collection, use this.moments.each().
Try removing the '()' when instantiate the collection.
this.moments = new Moments;
Also, as it's an asynchronous call, bind the collection's 'change' event with the rendering.
I hope it helps you.

Resources