Backbone.js set URL parameters in model & use it with fetch - backbone.js

I would like to fetch model from specific url with parameter:
url: server/somecontroller/id/?type=gift
Simple working way is:
collection.fetch({ data: { type: 'gift'} });
But I want to set it in model:
...
if(id){
App.coupon = new AffiliatesApp.Coupon({id: id});
} else {
App.coupon = new AffiliatesApp.Coupon({id: 'somecontroller'}, {type: 'gift'});
}
App.coupon.fetch();
How can I achieve it?

The easiest way to achieve this is to override Backbone's url method on the Coupon model with one defined by you. For example you can do :
Affiliates.Coupon = Backbone.Model.extend({
urlRoot : "server/somecontroller/",
url : function(){
var url = this.urlRoot + this.id;
if(this.get("type")){
url = url + "/?type=" + this.get("type");
}
return url;
}
});
This solution is easy to implement but has a drawback: the generated URL will be used for every action that syncs to the server (fetch,save,..).
If you need to have a finer control over the generation of the URL depending on what action you are doing you will need to override Backbone's Sync method for your model.

It can be done by overriding the fetch method in model to use some custom data. Using CoffeeScript it could look like this:
class AffiliatesApp.Coupon extends Backbone.Model
fetch: ->
super(data: { type: #get('type') })
Note that this example will ignore any attributes passed to coupon.fetch(), however it can be easily adjusted for any override logic.

Related

REST AngularJS #resource parametrized request

I have next WEB API:
GET List<EventHistory> '/service/eventhistories'
GET EventHistory '/service/eventhistories/{id}'
DELETE EventHistory '/service/eventhistories/{id}'
PUT EventHistory '/service/eventhistories'
POST EventHistory '/service/eventhistories'
Using angular i want use #resource to get information from server.
angularApp.factory('eventHistoryFactory', function ($resource) {
return $resource('/inner/service/eventhistories/:id',{id:'#id'});
});
But using this declaration i do not have any API to request the page based on some data.
var pageRequest = {
size: size,
page: page
};
or to send update for eventHistory entity.
Based on OP's comment:
Say you want to update a single entity:
.controller('someCtrl', function($stateParams, eventHistoryFactory){
//For the sake of the demonstration - id comes from the state's params.
var eventHistory = eventHistoryFactory.get({id: $stateParams.id});
eventHistory.$promise.then(function(){
//Modify the entity when HTTP GET is complete
eventHistory.address = 'New York';
//Post the entity
eventHistory.$save();
//If you wish to use PUT instead of POST you should declare that
//in the class methods of $resource
});
//Another example using query
var entries = eventHistoryFactory.query({
page: 0,
size: 20,
before: Date.now()
});
//This is translated into GET /inner/service/eventhistories?page=0&size=20&before=111111111111
//and should be interpreted correctly by your backend.
entries.$promise.then(function(){
//entries now contain 20 first event history with date earlier than now.
var specificEntry = entries[0];
//Same deal - modify the entity when HTTP GET is complete
specificEntry.address = 'New York';
//Post the entity
specificEntry.$save();
});
the first answer seems good, but i think this way more understandable and simply for begginers:
eventHistoryFactory.get(pageRequest, function (returnData) {
console.trace('request processed successfully: ' + returnData);
params.total(returnData.totalElements);
$defer.resolve(returnData.content);
}, function (error) {
console.log('request processed with error: ' + error);
})
to make page request in dynamic way the object should be build before request from ngTable current properties (use ngTable API).
Please pay your attention to eventHistoryFactory. It does not have parameter for pageRequest object, but it works -angular magic. By GET request in url you can see:
?page=2&size=25

why does backbone think I'm treating an object like a function?

Adding Backbone to a Rails app, I created a post model inside an app namespace like this
var app = {
this.models.post = new app.Models.Post();
In the router, I created the following route
"posts/:id": "postDetails"
When I navigate to /posts/4, I'm getting an Uncaught TypeError: object is not a function error when I try to call fetch on the model like this
postDetails: function (id) {
console.log(id);
var post = new app.models.post({id: id});
this.post.fetch({
success: function (data) {
$('#content').html(new PostView({model: data}).render().el);
}
});
}
According to the Backbone docs http://backbonejs.org/#Model-fetch, I should be able to call fetch on a model to retrieve the data from the server. Why does Backbone think I'm treating an object like a function?
You're doing this:
this.models.post = new app.Models.Post();
to, presumably, set app.models.post to an instance of the app.Models.Post model. Then you try to do this:
var post = new app.models.post({id: id});
But you can only use the new operator on a function:
new constructor[([arguments])]
Parameters
constructor
A function that specifies the type of the object instance.
You probably want to say:
var post = new app.Models.Post({ id: id });
or something similar.
The problem is you've declared post as a local variable var post, but then tried to access it as a member this.post. You need either this:
this.post = new app.models.post({id: id});
this.post.fetch({ ...
Or this:
var post = new app.models.post({id: id});
post.fetch({ ...
(The difference being that a local variable var post is declared in transient scope and thrown away after postDetails completes; while instance variable this.post gets added to the Router object and will typically live for the whole lifetime of the application.)

Backbone collection export issues

I have a collection of users (model user)
model has a boolean value: isExport
i have a button that on click supposed to post to the server all the users that isExport=true
Can anyone suggest a suitable solution for this problem?
I know it's possible to wrap the collection as a model and overwrite the toJSON function
but couldn't manage it so far (can someone please give a code example?)
App.User = Backbone.Model.extend({ defaults: {isExport: false}...});
App.Users = Backbone.Collections.extend({model: App.User...});
Thanks!
Roy
Backbone collections by default don't have any write operations to the server, so you'll need to add a new method to your Collection subclass such as doExport, use .where to get the models with isExport=true and their toJSON() to get an array of objects which you can then send to the server with Backbone.sync or $.post.
Backbone comes with RESTful support.
So, if you give each collection a url pointing to the collection rest service, then with a few functions (create,save) you can handle server requests.
App.Models.User = Backbone.Model.extend();
App.Collections.Users = Backbone.Collection.extend({
url: 'users',
model: App.Models.User
});
So, this way, you can:
var users = new App.Collections.Users();
users.fetch(); // This will call yoursite.com/users
// Expecting a json request
And then you can:
users.create({ name: 'John', isExport: true });
This will send a post request to the server, in order to create a new record.
And you can check on server side if it has the flag you want.
App.Views.ExportAll = Backbone.View.extend({
el: '#exportAll',
events: {
'click': 'exportAll'
},
exportAll: function(e){
e.preventDefault();
console.log('exporting all');
console.log(this.collection.toJSON());
var exportModel = new App.Models.Export;
exportModel.set("data", this.collection.toJSON());
console.log(exportModel.toJSON());
exportModel.save();
}
});
I think this is the best solution for the problem

Is it possible to add a route to the RouteCollection in MVC?

I couldn't think of a reasonable title for this post.
The problem I'm having is that I have an SQL database attached to my MVC website. Within the website I have a news/blog system that I have worked on which stores the data in the database and pulls the information on request.
The problem is the routing. I currently have it set up to pull the information about the routing of each individual page as this:
var newsr = new NewsResources();
foreach (var item in newsr.GetAllNewsItems())
{
item.Title = item.Title.Replace(' ', '-').ToLower();
routes.MapRoute(item.Title, "News/" + item.Title,
new {controller = "News", action = "Post", id = item.ID});}
When I add a new news item however, this doesn't go into the routing system which is proving to be a right pain. I've had a google search for dynamically adding url routing but I can't seem to find a solution.
What I want to know is, is it possible to add a page to the routing system via the page controller once I have saved the post into the database?
I do not think you need to Do a For Each loop across all your POst item and add routes for that. You may do it like this
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("SingleItem", "News/{title}",
new { controller = "Items", action = "PostFromTitle" });
// and the generic route
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index",
id = UrlParameter.Optional }
);
}
This will route ../News/SomeTitle request to your PostFromTitle action method of NewsController. Read the title there and get the post from there.
public ActionResult PostFromTitle(string title)
{
var post=repo.GetPostFromTitle(title);
return View("~/Views/News/Post.cshtml",post);
}
It may be better to an action that takes a title as a parameter.
routes.MapRoute("NewsItem", "News/{title}",
new { controller = "News", action = "ShowNews" }

Setting parameters on collection methods using Backbone.Rpc

Using the Backbone.Rpc plugin [ https://github.com/asciidisco/Backbone.rpc ] I am attempting to send parameters on the read method when fetching a collection. When working with a single model instance you can add parameters to a method call by setting the value of a model attribute.
var deviceModel = Backbone.model.extend({
url: 'path/to/rpc/handler',
rpc: new Backbone.Rpc(),
methods: {
read: ['getModelData', 'id']
}
});
deviceModel.set({id: 14});
deviceModel.fetch(); // Calls 'read'
// Request created by the 'read' call
{"jsonrpc":"2.0","method":"getModelData","id":"1331724849298","params":["14"]};
There is no corresponding way that I am aware of, to do a similar thing prior to fetching a collection as there is no 'set' method available to backbone collections.
var deviceCollection = Backbone.collection.extend({
model: deviceModel,
url: 'path/to/rpc/handler',
rpc: new Backbone.Rpc(),
methods: {
read: ['getDevices', 'deviceTypeId']
}
});
// This is not allowed, possible work arounds?
deviceCollection.set('deviceTypeId', 2);
deviceCollection.fetch();
// Request created by the 'read' call
{"jsonrpc":"2.0","method":"getDevices","id":"1331724849298","params":["2"]};
Is it possible to pass parameters to collection methods using Backbone.Rpc? Or do I need to pass collection filters in the data object of the fetch method?
I updated Backbone.Rpc (v 0.1.2) & now you can use the following syntax to add "dynamic"
arguments to your calls.
var Devices = Backbone.Collection.extend({
url: 'path/to/my/rpc/handler',
namespace: 'MeNotJava',
rpc: new Backbone.Rpc(),
model: Device,
arg1: 'hello',
arg2: function () { return 'world' },
methods: {
read : ['getDevices', 'arg1', 'arg2', 'arg3']
}
});
var devices = new Devices();
devices.fetch();
This call results in the following RPC request:
{"jsonrpc":"2.0","method":"MeNotJava/getDevices","id":"1331724850010","params":["hello", "world", "arg3"]}
Ah,
okay, this is not included at the moment, but i can understand the issue here.
I should be able to add a workaround for collections which allows the RPC plugin to read
collection properties.
var deviceCollection = Backbone.collection.extend({
model: deviceModel,
url: 'path/to/rpc/handler',
rpc: new Backbone.Rpc(),
deviceTypeId: 2,
methods: {
read: ['getDevices', 'deviceTypeId']
}
});
Which will then create this response:
{"jsonrpc":"2.0","method":"getDevices","id":"1331724849298","params":["2"]};
I will take a look this evening.

Resources