A config file to hold all REST apis - javascript

I have lot of Backbone models like these:
var register = Backbone.model.extend({
url: http://....../register/
});
var login = Backbone.model.extend({
url: http://....../login/
});
My question is:
Can i have a separate file to hold all urls? Like a file which holds all the urls and I can request with a variable name as needed? Is it a bad approach? I want to be able to change these apis without going to model file(s) individually.

you can have a file, for instance, appUrl like this:
app.urls = {
registerUrl: "/register",
loginUrl: "/login"
}
and your model:
var register = Backbone.model.extend({
url: function(){
return app.urls['registerUrl']
}
});

One way to approach this is to pass in the URL in the instantiation of the model, rather than declaring explicit models for each. That would look something like:
var BaseModel = Backbone.Model.extend({
// My shared model properties
});
var myNewModel = new BaseModel(null, {
url: '/my-url-for-new-model'
});
Alternately, you can have the url parameter be a function, and then return the appropriate URL. That could be something like this:
var urls = {
register: '/some-url/register/',
login: '/some-url/login'
};
var BaseModel = Backbone.Model.extend({
initialize: function(data, config) {
this.modelType = config.type;
}
url: function() {
return urls[this.modelType];
}
});
var loginModel = new BaseModel(null, {
type: login
});

Related

LocalStorage and URL in one Backbone collection

I have a collection, which fetches data from URL.
BarCollection = Backbone.Collection.extend({
model: BarModel,
url: // Some URL
});
But the problem is that I want to fetch data to this collection not only from URL, but also from local storage. I wish I could do something like that:
BarCollection = Backbone.Collection.extend({
model: BarModel,
url: // Some URL,
localStorage: new Backbone.LocalStorage('bars')
});
But .fetch() method cannot get data both from url and local storage.
Simple workaround is to create two different collections: one for URL and one for local storage. And after fetching just merge them.
BarCollection = Backbone.Collection.extend({
model: BarModel,
url: // Some URL
});
LocalBarCollection = Backbone.Collection.extend({
model: BarModel,
localStorage: new Backbone.LocalStorage('local-contributors')
});
I wonder if there is a more beautiful way of doing that.
To enable any collection or model to synchronize from both the localStorage and a server, Backbone's sync function can be overridden:
Backbone.sync = (function(sync) {
return function(method, model, options) {
options = options || {};
var key = _.result(model, 'localStorage'),
response;
// if the localStorage property exist on the model/collection
// first try to sync with the localStorage
if (key) {
switch (method) {
case 'create':
case 'update':
var data = model.toJSON(),
text = JSON.stringify(data);
localStorage.setItem(key, text);
break;
case 'delete':
localStorage.removeItem(key);
break;
case 'read':
response = JSON.parse(localStorage.getItem(key));
if (response) model.set(response, { parse: true });
break;
}
}
// then, always sync with the server as it normally would
return sync.apply(this, arguments);
};
})(Backbone.sync);
This way, if a model or a collection as a localStorage property, it'll first sync with the localStorage, then it'll make the original sync.
Example model and collection:
var BarModel = Backbone.Model.extend({
urlRoot: 'some/url',
localStorage: function() {
return 'bars-' + this.id;
},
});
var BarCollection = Backbone.Collection.extend({
model: BarModel,
url: '/some/url',
localStorage: 'bars',
});

Send PUT request with Backbone

I have to make service call with backbone to update user settings. here is the simplified code:
var settingService = Backbone.Model.extend({
"url": "usersettings"
});
var SettingsView = Backbone.View.extend({
initialize: function() {
this.services = {
"userSettingsService": new settingService()
};
},
saveSettings: function() {
this.services.userSettingsService.save({
"currency": "USD",
"dateFomat": "DD-MM-YYYY"
})
}
});
var settings_view = new SettingsView();
settings_view.saveSettings();
http://jsfiddle.net/ovg3kyqz/2/
when I call saveSettings the POST request is made which is not supported by backend. I need to make PUT request. I know that Backbone decides whether model is new based on its id and if so will send a PUT request
I can set
this.services.userSettingsService.set("id", 1)
and then on saveSettings a PUT request will be made but the request body will have {id: 1,...} which is not really what I want.
so how can I make a PUT request and not include id in the request body?
You could simply override the isNew method on your model to always return false and thus always send a PUT request. Something like
var settingService = Backbone.Model.extend({
url: "usersettings",
isNew: function () {
return false;
}
});
And a demo http://jsfiddle.net/ehhwqm70/
An alternative to overriding isNew (that I find more explicit) would be to override model.sync:
var settingService = Backbone.Model.extend({
url: "usersettings",
sync: function(method) {
if (method === "create") {
arguments[0] = "update";
}
return Backbone.sync.apply(this, arguments);
}
});
Demo: http://jsfiddle.net/pytpfnar/1/

What is the best way to add server variables (PHP) in to the Backbone.model using require.js?

I'm not sure what is the elegant way to pass server variables in to my Model.
For example, i have an id of user that has to be implemented on my Model. But seems like Backbone with require are not able to do that.
My two options are:
Get a json file with Ajax.
Add the variable on my index.php as a global.
Someone know if exists a other way. Native on the clases?
Trying to make work the example of backbonetutorials. I am not able to throw a callback when the method fetch().
$(document).ready(function() {
var Timer = Backbone.Model.extend({
urlRoot : 'timeserver/',
defaults: {
name: '',
email: ''
}
});
var timer = new Timer({id:1});
timer.fetch({
success: function(data) {
alert('success')
},
fail: function(model, response) {
alert('fail');
},
sync: function(data) {
alert('sync')
}
});
});
The ajax request it has been threw. But does not work at all. Because any alert its dispatched.
var UserModel = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
name: '',
email: ''
}
});
// Here we have set the `id` of the model
var user = new Usermodel({id: 1});
// The fetch below will perform GET /user/1
// The server should return the id, name and email from the database
user.fetch({
success: function (user) {
console.log(user);
}
})
The server will reply with a json object then you can leave the rendering part for your backbone. Based on a template for the user.
You may also want to check these out: http://backbonetutorials.com/

Fetch collection only one time

i've a userlist made by a fetch from parse.com and rendered by view.Once people click on item list i've insert in url the objectid. In router i've made a function "home" that make fetch from collection and call view to render.The function "userdetails" catch objectid previous insert by view in url and use it to make a get from collection. The problem is:how can i pass the collection to this function userdetails?I don't want make another fetch.
home: function() {
var self=this;
console.log("inrouterhome");
var utenti = new Usercollection();
utenti.fetch({
success: function(object) {
var page=new Homelistuser({model:object});
self.changePage(page);
},
error: function(amici, error) {
// The collection could not be retrieved.
}
});
},
userDetails: function (objectId) {
HERE I WANNA USE OBJECTID TO MAKE A GET FROM COLLECTION FETCHED IN HOME
},
It looks like it is probably a scoping issue. Try this
var Models = {};
var AppRouter = Backbone.Router.extend({
home: function() {
var self=this;
console.log("inrouterhome");
Models.utenti = new Usercollection();
Models.utenti.fetch({
success: function(object) {
var page=new Homelistuser({model:object});
self.changePage(page);
},
error: function(amici, error) {
// The collection could not be retrieved.
}
});
},
userDetails: function (objectId) {
//Models.utenti should exist as long as home came first,
// may want to write a condition that check to see if it exists and if not do fetch.
}
});
As #abritez mentioned this is probably a scoping problem i.e. the userDetails method doesn't have access to the instantiated collection. #abritez's solution resolves this but if the user refreshes the page or accesses the route directly the collection will not be loaded.
If the collection is used between both routes consider fetching it at run time and using a listener for when it's ready:
var Models = {};
Models.utenti = new Usercollection();
Models.utenti.fetch();
var AppRouter = Backbone.Router.extend({
home: function() {
var utentiLoaded = function(object) {
var page = new Homelistuser({model:object});
this.changePage(page);
}
this.listenTo(Models.utenti, 'reset', utentiLoaded);
this.listenTo(Models.utenti, 'error', function(amici, error) {
// The collection could not be retrieved.
});
if (Models.utenti.any()) {
utentiLoaded(Models.utenti);
}
},
userDetails: function(objectId) {
var utentiLoaded = function(object) {
}
this.listenTo(Models.utenti, 'reset', utentiLoaded);
this.listenTo(Models.utenti, 'error', function(amici, error) {
// The collection could not be retrieved.
});
if (Models.utenti.any()) {
utentiLoaded(Models.utenti);
}
}
});

Nested Model in Backbone.js

I want to map JSON having hierarchical structure onto Model. I can map the data at a top hierarchy onto Model. However, I can't map it onto Model which nested the element which I nested.
JSON
{
"attr1":"data1",
"chi1": {
"attr1":"chi1_data"
},
"list1":[
{"name":"name1"},
{"name":"name2"}
]
}
JavaScript
var Child2 = Backbone.Model.extend({
fun1:function() {
alert("this is Child2");
}
});
var List1 = Backbone.Collection.extend({
url: "list1",
model: Child2,
fun1:function() {
alert("this is List1");
}
});
var Child1 = Backbone.Model.extend({
});
var Root1 = Backbone.Model.extend({
url: "sample.json",
defaults : {
list1 : new List1,
chi1 : new Child1,
}
});
var View1 = Backbone.View.extend({
el: "#friends",
events: {
"click button": "sample"
},
initialize: function() {
this.root1 = new Root1();
},
sample: function() {
this.root1.fetch({
success: function(model) {
// this is success
alert(model.get("attr1"));
// this is error
alert(model.get("list1").fun1());
// this is error too.
model.get("list1").each(function(attr) {
alert(attr.fun1());
});
},
error: function(model, res) {
alert("error: " + res.status);
}
});
},
});
You might want to take a look at this plugin.
http://documentup.com/afeld/backbone-nested/
Might not be exactly what you want, but it could at least point you in the right direction.
The other thing you can do is override the parse method on your model...
parse: function(resp){
// And setup the model using the raw resp
// The resp data is your json from the server and will
// be used to setup the model. So overriding parse, you can
// setup the model exactly they way you want.
return resp;
}
thank you jcreamer.
backbone-nested plugin seems to be different from what I want to do.
I can realize the nest of the model. In using parse function.
// it is able to get "chi1_data"
new Child2(JSON.parse(JSON.stringify(resp["chi1"]))).get("attr1")
// it is able to get "name2"
new Child2(JSON.parse(JSON.stringify(new List1(JSON.parse(JSON.stringify(resp["list1"]))).get(2)))).get("name")
I found Backbone-relational plug in. I will try this
https://github.com/PaulUithol/Backbone-relational

Categories

Resources