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

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

Related

Backbone.js / require.js - Override model function to work with backend as a service

Good morning guys. I have a little understanding problem with backbone.js. i have a javascript sdk from a backend as a service with some getter and setter methods to get datas from this platform.
I have load this javascript sdk with require.js an it´s work fine. Now i need to create some models that work with this getter and setter methods to get this data to my collection an finally to my view. I do not have any clue...maybe someone have the right idea for me.
This is my current model:
define(['jquery','underscore','backbone'], function($,_,Backbone) {
var holidayPerson = Backbone.Model.extend({
initialize: function() {
console.log("init model holidayPerson");
this.on("change", function(data) {
console.log("change model holidayPerson"+JSON.stringify(data));
});
}
});
return holidayPerson;
});
Actually i create an instance of my model in my view:
define(['jquery','underscore','backbone','text!tpl/dashboard.html','holidayPerson','apio'], function($,_,Backbone,tpl, holidayperson, apio) {
template = _.template(tpl);
var usermodel = new holidayperson();
var dashboardView = Backbone.View.extend({
id: 'givenname',
initialize: function() {
console.log("dashboard view load");
usermodel.on('change', this.render);
var user = new apio.User();
user.setUserName('xxx');
user.setPassword('xxx');
apio.Datastore.configureWithCredentials(user);
apio.employee.getemployees("firstName like \"jon\" and lastName like \"doe\"", {
onOk: function (objects) {
console.log("apio: " + JSON.stringify(objects));
usermodel.set({mail: objects[0]['data']['mail'],lastname: objects[0]['data']['lastName'], username: objects[0]['data']['userName'], superior: objects[0]['data']['superior']});
}
});
},
render: function() {
console.log("render dashboard view");
console.log(usermodel.get('mail'));
console.log(usermodel.get('lastname'));
this.$el.html(template());
return this;
}
});
return dashboardView;
});
I think this not the right way...can i override the getter and setter method from this model ? Or maybe the url function ? Anyone now what is the best practice ?
Thanks a lot :-)
First of all, make sure that your render operation is asynchronous, as your API call will be and the usermodel params won't be set until that operation completes. If you render method fires before that, it will render the empty usermodel, since the data will not be there yet.
Second, a model need not fetch its own data, in my opinion. If you are going to have multiple users, you could use a collection to hold those users and then override the collection's sync method to handle the fetching of data from the API, but if there's no collection, it seems logical to me to have a method that does the data fetching and setting thereafter, as you've done.

Backbone.js: just one line to set local storage?

demo fiddle (with problem) http://jsfiddle.net/mjmitche/UJ4HN/19/
I have a collection defined like this
var Friends = Backbone.Collection.extend({
model: Friend,
localStorage: new Backbone.LocalStorage("friends-list")
});
As far as I'm aware, that's all I need to do to get local storage to work (in addition to including it below backbone.js)
One thing I wasn't sure about, does the name "friends-list" have to correspond to a DOM element? I'm trying to save the "friends-list" so I called it that in local storage, however, localstorage doesn't seem to require passing a class or an id.
Here's a fiddle where you can see what I'm trying to do http://jsfiddle.net/mjmitche/UJ4HN/19/
On my local site, I'm adding a couple friends, refreshing the page, but the friends are not re-appearing.
Update
I've also done the following in my code on my local site
console.log(Backbone.LocalStorage);
and it's not throwing an error.
My attempt to debug
I tried this code (taken from another SO answer) in the window.AppView but nothing came up in the console.
this.collection.fetch({}, {
success: function (model, response) {
console.log("success");
},
error: function (model, response) {
console.log("error");
}
})
From the fine manual:
Quite simply a localStorage adapter for Backbone. It's a drop-in replacement for Backbone.Sync() to handle saving to a localStorage database.
This LocalStorage plugin is just a replacement for Backbone.Sync so you still have to save your models and fetch your collections.
Since you're not saving anything, you never put anything into your LocalStorage database. You need to save your models:
showPrompt: function() {
var friend_name = prompt("Who is your friend?");
var friend_model = new Friend({
name: friend_name
});
//Add a new friend model to our friend collection
this.collection.add(friend_model);
friend_model.save(); // <------------- This is sort of important.
},
You might want to use the success and error callbacks on that friend_model.save() too.
Since you're not fetching anything, you don't initialize your collection with whatever is in your LocalStorage database. You need to call fetch on your collection and you probably want to bind render to its "reset" event:
initialize: function() {
_.bindAll(this, 'render', 'showPrompt');
this.collection = new Friends();
this.collection.bind('add', this.render);
this.collection.bind('reset', this.render);
this.collection.fetch();
},
You'll also need to update your render to be able to render the whole collection:
render: function() {
var $list = this.$('#friends-list');
$list.empty();
this.collection.each(function(m) {
var newFriend = new FriendView({ model: m });
$list.append(newFriend.render().el);
});
$list.sortable();
return this;
}
You could make this better by moving the "add one model's view" logic to a separate method and bind that method to the collection's "add" event.
And a stripped down and fixed up version of your fiddle: http://jsfiddle.net/ambiguous/haE9K/

backbone boilerplate render view issue

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.

Query Database with Backbone Collection

I need to query the database using a backbone collection. I have no idea how to do this. I assume that I need to set a url somewhere, but I don't know where that is. I apologize that this must be a very basic question, but I took a backbone course on CodeSchool.com and I still don't know where to begin.
This is the code that I have for the collection:
var NewCollection = Backbone.Collection.extend({
//INITIALIZE
initialize: function(){
_.bindAll(this);
// Bind global events
global_event_hub.bind('refresh_collection', this.on_request_refresh_collection);
}
// On refresh collection event
on_request_refresh_collection: function(query_args){
// This is where I am lost. I do not know how to take the "query_args"
// and use them to query the server and refresh the collection <------
}
})
The simple answer is you would define a URL property or function to your Backbone.Collection like so:
initialize: function() {
// Code
},
on_request_refresh_collection: function() {
// Code
},
url: 'myURL/whateverItIs'
OR
url: function() {
return 'moreComplex/' + whateverID + '/orWhatever/' + youWant;
}
After your URL function is defined all you would have to do is run a fetch() on that collection instance and it will use whatever you set your URL to.
EDIT ------- Making Collection Queries
So once you set the URL you can easily make queries using the native fetch() method.
fetch() takes an option called data:{} where you can send to the server your query arguments like so:
userCollection.fetch({
data: {
queryTerms: arrayOfTerms[], // Or whatever you want to send
page: userCollection.page, // Pagination data
length: userCollection.length // How many per page data
// The above are all just examples. You can make up your own data.properties
},
success: function() {
},
error: function() {
}
});
Then on your sever end you'd just want to make sure to get the parameters of your request and voila.

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