Why backbone add extra parameter to url path? - backbone.js

I am using backbone.marionette (1.0.0) and node.js (0.10.22). Wondering why backbone add extra parameter when I try to save model data with node.js REST call.
model.js
Backbone.Model.extend ({
urlRoot: function (){
return '/path/' + myApp.companyId;
},
defaults: {
companyId: '',
// other attributes
},
// doesn't use 'id' in model instead companyId
idAttribute: 'companyId'
});
Before view is loaded, I would request model data with myApp.request ('entities:myModel') which issued model.fetch () and node.js backend would fire GET /path/1 route. No issue.
However, when an update button is clicked on the view, this.model.save () would fired PUT /path/1/1. It should be PUT /path/1, with only a single '1' in url path.
view.js:
clicked: function () {
var formData = Backbone.syphon.serialize (this);
this.model.set (formData);
var promise = this.model.save ();
promise.done ().fail ()
}
How can I stop backbone.sync from appending extra parameter to url path? Thanks for taking time out to read this, and I appreciate your help.

You're setting urlRoot incorrectly on the model. It should be
Backbone.Model.extend ({
urlRoot: "path",
// etc
});
Backbone willa dd the ids on it's own.
If you want to specify the ids in your function, use the url function.

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.

Loading Backbone model by custom attribute

Lets say, I have the following Backbone model :
var Meal = Backbone.Model.extend({
defaults: {
"appetizer": "caesar salad",
"entree": "ravioli",
"dessert": "cheesecake"
},
urlRoot : api/meals,
idAttribute : id,
// some other stuff
});
Assuming that I have a backend Spring MVC conroller that intercept GET requests, so when I fetch my model, using
myMeal.fetch();
my model gets loaded from the server.
for now everything is clear, my question is, what if I have another method on the backend that takes a string as parameter and return as responsebody, the right json element.
how can I make that call from my model ?
I'm looking for something like this :
var meal = new Meal({'entree': 'value'});
meal.fetch({
// if there is no id, and 'entree' is given, I want to call /
// api/findByEntree passing this.entree as parameter.
});
I want to make an Ajax call from the object itself to the backend, by specifying the url inside the Backbone model.
urlRoot can be a function so no need to override fetch. I believe you could just do something like this:
var Meal = Backbone.Model.extend({
defaults: {
"appetizer": "caesar salad",
"entree": "ravioli",
"dessert": "cheesecake"
},
urlRoot : function() {
return 'api/' + this.get('id') ? 'meals' : 'findByEntree';
},
idAttribute : id,
// some other stuff
});
You can override the default fetch, intercept the call, do some verification and then pass onto the original fetch:
var Meal = Backbone.Model.extend({
fetch: function(options) {
if(this.has('id')) {
Backbone.Model.prototype.fetch.call(this, options);
} else {
this.findByEntree(options);
}
},
fetchByEntree: function(options) {
...
}
});
however, keep in mind that you'll need some extra logic to deal with the case of trying to fetch a new Meal, which won't have neither id nor entree.

How to fetch the model in a view with a dynamic url defined in a view

I am using backbone.js in my app. My model named MyModel is
Backbone.Model.extend({
urlRoot: 'home'
});
Need to fetch model with url "home/abc/xyz" where "abc" and "xyz" are dynamic in my view. I did the following
var model = new MyModel({id:'abc/xyz'});
model.fetch();
but its not working.
It goes to url "home/abc?xyz".
How should i solve this issue?
Here is the url function of Backbone.Model which is responsible for such kind of behavior in Backbone:
url: function() {
var base =
_.result(this, 'urlRoot') ||
_.result(this.collection, 'url') ||
urlError();
if (this.isNew()) return base;
return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
}
As you can see encodeURIComponent(this.id) will encode your id, so you can't pass and '/' -> '%2F'.
You always can rewrite this function, but I guess it's not the best idea, cause it can break another things.
I can suggest you another approach:
Just define urlRoot of your model as function and there do your job:
var yourModel = Backbone.Model.extend({
defaultUrl: 'home',
urlRoot: function () {
return defaultUrl + this.get('yourUrlAttribute');
}
});
Just pass the yourUrlAttribute as model attribute when creating it and fetch the model.
Having in mind this approach and that Backbone.Model will append encoded 'id' as the last part of URL (when you fetching model) you can get what you want.

Cannot access all backbone model attributes from template

The problem I am trying to debug is that, in my backbone view, all the model attributes (name, id, email etc) are available, (I have console.log() the model attributes to verify this), however, when I render the view passing the model, only the name attribute is available in the template, all other attributes are undefined,please is there any thing I am missing, as this is my first backbone application and I have spent hours trying to debug this and have gone through many tutors online and my code seems correct, thanks
//BACKbone view method(I have verified and all the model values are available here)
var profileView=Backbone.View.extend({
el:$('#content'),
initialize:function(){
this.model.bind('change',this.render,this);
},
render:function(){
var self=this;
this.$el.html(_.template(profileTemplate,this.model.toJSON()));
}
});
//HTML TEMPLATE (profileTemplate), only the name attribute is available in the template, //browser gives an error of 'undefined' for all other attributes except the name attribute
<h1><%=name.first%> <%=name.last%> </h1>//displays correctly
<%=email%> //undefined
//SCHEMA
var AccountSchema=new mongoose.Schema({
email:{type:String,unique:true},
password:{type:String},
name:{
first:{type:String},
last:{type:String},
full:{type:String}
},
});
//IT IS SOLVED NOW, IT happened because I executed the fetch command on the model after calling the render method instead of before calling the render method
This is my router, I call the model.fetch() from the router after the view is created. The problem stopped when I called model.fetch() before the rendering of the before
define([''views/profile''],function(,ProfileView){
var router = Backbone.Router.extend({
currentView: null,
socketEvents: _.extend({}, Backbone.Events),
routes: {
'addcontact': 'addcontact',
'index': 'index',
'login': 'login',
'register': 'register',
'forgotpassword': 'forgotpassword',
'profile/:id': 'profile',
'contacts/:id': 'contacts',
"upload/:id":"upload"
},
profile: function(id) {
var model = new Account({id:id});
console.log('profile user:'+id);
this.changeView(new ProfileView({model:model})); //View is created here
model.fetch(); // model is fetched after view is rendered, cause for the problem in my case
}
});
return new router();
});

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.

Resources