I don't get how to make Backbone.sync suitable for my case.
That's why I still use this usual Ajax-Request for my project:
$.ajax({
url: request,
status: status,
type: 'GET',
dataType: 'json',
beforeSend: function (req) { req.setRequestHeader("Authorization", auth) },
success: function (data, status) {
//update the model
},
error: function(XMLHttpRequest, textStatus, errorThrown){
//do stuff
}
});
I need to add a base64 encoded authorization to the request header and update a model. The data I get from the server contain more information than my model needs. That's why I can't refer the model directly to an url like this:
var MyApp.myModel = Backbone.Model.extend({
url: '/someResourceUrl'
});
MyApp.myModel.fetch();
I need to do sth. like:
var MyApp.myModel = Backbone.Model.extend({
url: 'anyurl',
sync: myOwnSpecificSync,
});
//Define the sync function:
myOwnSpecificSync = function(method, model, options) {
//add header
//return only specific parameters of the success data
};
//let the model fetch the data from the server
MyApp.myModel.fetch();
But I have no idea how to implement the functions .. or if it's correct at all.
var AuthSync = function(method, model, options) {
options.beforeSend = function () {
console.log('add auth header here');
};
return Backbone.sync(method, model, options);
};
var Model = Backbone.Model.extend({
url : 'http://fiddle.jshell.net/echo/json/',
sync : AuthSync
});
new Model().fetch();
Related
Hey I want to change the data before sending it with ngResource (build FormData object). I do everything as in the examples that I found, however I can't make them work. Here is my code:
My controller where I set the data and try to send them:
var vm = this;
vm.application = new Application();
vm.application.title = 'Test title';
Application.save({}, vm.application, function(){
});
My service:
function application(ApiBaseUrl, $resource) {
var actions = {
'save': {
metod: 'POST',
url: ApiBaseUrl + "/applications",
headers: { 'Content-Type': false },
transformRequest: function (data) {
console.log(data); //Returns 'undefined'
return data;
}
}
};
return $resource(ApiBaseUrl + "applications/:id", {}, actions);
}
In the function transformRequest data object is always marked as 'undefined'. Am I doing something wrong? Is there a better way to edit the data before sending it?
The problem was I had
metod: 'POST'
when I should have used:
method: 'POST'
The rest interface I'm currently working has something like this,
Returns a collection
POST /base/Holiday/getHolidaySetup/
FORM_DATA: client_id:1
Even worse..
POST /base/Holiday/setAddHoliday/
FORM_DATA: client_id:1
... other form data..
Clearly in a newer scheme, it'd look something like
/base/Holiday/client/
POST to create a new holiday.
/base/Holiday/client/
GET To retrieve holidays
But, that's just not what we're working with..
So how do I set Backbone up for such a scheme.
You can completely change how your models and collections handle their persistence by overriding their respective sync methods.
For example, to fetch a collection
var M = Backbone.Model.extend({
idAttribute: "client_id"
});
var C = Backbone.Collection.extend({
model: M,
url: "/base/Holiday/getHolidaySetup/",
sync: function(method, model, options) {
var params = {
type: 'POST',
dataType: 'json',
data: JSON.stringify({client_id: 1}),
url: _.result(this, 'url'),
processData: false
};
var xhr = Backbone.ajax(_.extend(params, options));
model.trigger('request', model, xhr, options);
return xhr;
}
});
http://jsfiddle.net/7L9v5rkz/5/
or to save a model
var M = Backbone.Model.extend({
idAttribute: "client_id",
url: '/base/Holiday/setAddHoliday/',
sync: function(method, model, options) {
options = options || {};
var params = {
type: 'POST',
dataType: 'json',
processData: false
};
if ((method === 'create') || (method === 'update')) {
params.url = _.result(this, 'url');
params.data = JSON.stringify(this.toJSON(options));
} else {
// handle read and delete operations
}
var xhr = Backbone.ajax(_.extend(params, options));
model.trigger('request', model, xhr, options);
return xhr;
}
});
http://jsfiddle.net/7L9v5rkz/2/
I'm have the following backbone model
define(["jquery", "underscore", "backbone"],
function ($, _, Backbone) {
var file_upload = Backbone.Model.extend({
url: 'http://localhost:8080/rest/customForms'
});
return file_upload;
}
I have a view loaded at
localhost:38559/app/forms.html
which tries to do a post with the following code
var fd = document.getElementById('fileToUpload').files[0];
var file = new file_upload();
file.fetch({data: $.param({fileToUpload: fd}),
type: 'POST',
success: function(d){
console.log('success');
}
});
but this seems to just do a get request to forms.html passing fd as a param. I've also tried overriding the sync method in file_upload
sync: function (method, model, options) {
var self = this;
options = _(options).clone();
var error = options.error;
options.error = function (jqXHR, textStatus, errorThrown) {
alert('error');
if (error)
error(jqXHR, textStatus, errorThrown);
};
var success = options.success;
options.success = function (data, textStatus, jqXHR) {
if (success && data) {
alert("Success uploading form.");
success(data, textStatus, jqXHR);
}
else
alert("Error uploading form. Please try entering again.");
};
var params = {
type: 'POST'
};
$.ajax(_.extend(params, options));
}
}
I'm doing posts in other parts of the app with similar code so can't figure out why with this code the fetch does a get request to the page it's called on rather than a post to the url specified in the model. Does anyone have any ideas?
Thanks,
Derm
Ugh - finally found the issue coming back to this. The file upload was been done on a button click event. I needed to call preventdefault to force the use of the models url rather than the pages url. Annoying issue - dunno how I missed it! Code now is
uploadForm: function (e) {
e.preventDefault();
var self = this;
var fd = document.getElementById('fileToUpload').files[0];
var file = new file_upload();
file.fetch({data: $.param({fileToUpload: fd}),
type: 'POST',
success: function(d){
console.log('success');
}
});
},
var COLLECTION = Backbone.Collection.extend({
url: "example.com",
sync: function(method, model, options){
params = _.extend({
type: "get",
url: this.url,
async: false,
dataType: "jsonp",
jsonpCallback : "jsonp_callback",
},options);
return $.ajax(params);
},
parse:function(response){
console.log(response);
return response;
}
});
var a = new COLLECTION();
var b = new COLLECTION();
$.when(a.fetch(),b.fetch()).done(function(){ console.log('done'); });
I have two questions:
In sync function, $.ajax(params) response TypeError: a["reset"] is not a function #0.9.10
Use multiple collection.fetch sometimes happen a.fetch() or b.fetch() response parse error
Thanks!!
Backbone.js's default, RESTful approach to fetching a model by the ID is easy and straight-forward. However, I can't seem to find any examples of fetching a model by a different attribute. How can I fetch a Backbone.js model by a different attribute?
var Widget = Backbone.Model.extend({
urlRoot: '/widgets',
fetchByName: function(){ ... }
});
var foowidget = new Widget({name: 'Foo'});
foowidget.fetchByName();
You can try doing something like this on your base model definition or on demand when calling fetch.
model.fetch({ data: $.param({ someParam: 12345}) });
In your case, along the lines of.
var Widget = Backbone.Model.extend({
initialize: function(options) {
this.name = options.name;
},
urlRoot: '/widgets',
fetchByName: function(){
this.fetch({ data: $.param({ name: this.name }) })
}
});
var foowidget = new Widget({name: 'Foo'});
foowidget.fetchByName();
One approach is to override Backbone.sync() method, either for all classes or for just your class. However, presumably your goal is to override fetch for just a single model. One way to do that is to directly call jQuery.ajax(...), and on success, take the response and set that, e.g.
fetchByName: function() {
var self = this;
$.ajax({
url: self.urlRoot+ "?name="+this.get('name'),
type: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function(data) {
self.set(data);
}
});
}
If the model is part of a collection you can use where() to pull out the models matching some criteria.
See http://backbonejs.org/#Collection-where
I really like the approach suggested by 'user645715'. I have adjusted the code to be more versatile. If you add this to a Backbone Model it will allow you to search the server by one or more attributes, and should work as a direct drop-in replacement for fetch.
fetchByAttributes: function(attributes, callbacks) {
var queryString = [];
for(var a in attributes){
queryString.push( encodeURIComponent(a)+'='+encodeURIComponent(attributes[a]) );
}
queryString = '?'+queryString.join('&');
var self = this;
$.ajax({
url: this.urlRoot+queryString,
type: 'GET',
dataType: "json",
success: function(data) {
self.set(data);
callbacks.success();
},
error: function(data){
callbacks.error();
}
});
}
It can be used like this:
var page = new Page();
page.fetchByAttributes({slug:slug}, {
success: function(){
console.log('fetched something');
},
error: function(){
console.log('nothing found');
}
});
this is simple model.fetch is same as $.ajax in some way
model = Backbone.Model.extend({
urlRoot: "/root/"
});
var Model = new model();
Model.fetch({
beforeSend: function () {
console.log("before");
},
data: {
param1: "param1",
param2: "param2"
},
success: function () {
console.log("success");
},
error: function () {
console.log("failure");
}
});