I am trying to pull JSON data and display on my console just to see if its working. I am seeing an error message.
I am trying to fetch a Model with id 1:
var TeamModel = Backbone.Model.extend({
urlRoot: '/json/team.json'
});
//Create Team Model Instance with id of team
var teamModel = new TeamModel({
id: 1
});
//Fetch the json data
teamModel.fetch();
var director = teamModel.get('name');
Here is the JSON file :
{
"id" : 1,
"name" : "Sam",
"img_small" : "images/sam.jpg",
"location" : "NYC",
"role" : "Director, Producer, & Writer",
}
This yields the following error :
GET http://localhost:9000/json/team.json/1 404 (Not Found)
You should use url, not urlRoot:
var TeamModel = Backbone.Model.extend({
url: '/json/team.json'
});
Backbone uses urlRoot to generate resource URLs based on the operation you perform (fetch, save, delete) and Model id. When you fetch a single Model, the URL it generates is urlRoot + '/' + id.
Therefore when you attempt to fetch a Model with id 1, the constructed URL is /json/team.json/1
If you set url, however, Backbone always uses that url. It does not change it based on operation or model attributes. This is the behaviour that you need, because you have a single static resource.
Related
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
I'm using $resource to fetch json data from a backend server.
First, I get a list of ids, with a first resource call. Then, for each id received, I use $resource to fetch data associated with this id.
Now, the problem is : I would like to associate the response with the id sent, so I can record data into a hashtable. (eg: $scope.table[response.id] = data; ). The only way I've found, is to have the API send back the id in the json response, but I'd like to associate the id with the query, so I know for which id is the response I got, without having the API to send it back.
Here is my current code (simplified, just to get the idea) :
// the factory. eg I send /rest/item/12345
app.factory('Item', function ($resource) {
return $resource("/rest/item/:id", { id: '#id'})
});
// the call (in a loop)
// I need to get { "id" : 12345, "text" : "blahblahblah" }
Item.get({ id : itemId },
function(data){
$scope.table[data.id] = data;
});
I would like to write something like this :
// the call (in a loop).
// I would like to only need to get { "text" : "blahblahblah" }
Item.get({ id : itemId },
function(id, data){
$scope.table[id] = data;
});
I guess I could use this form :
$scope.table[itemId] = Item.get({id : itemId});
But I need $scope.table[itemId] to be a "correct" value all the time, not a promise, and I want it to be updated just when I receive the answer.
Is it possible ?
something like this might work:
// get the array of ids
ItemIds.get({},
function(ids){
// for each id, make the request for the actual item
ids.forEach(function(id) {
Item.get({ id : id },
function(data){
// in this nested callback, you have access to data and id
$scope.table[id] = data;
});
});
});
I'm looking to fetch a subset of a backbone collection using the model's URL.
Similar to the tutorial of "Nested Collections" found at:
http://liquidmedia.org/blog/2011/01/backbone-js-part-1/
Since this requires data api, models, collections, views i've included my full code of what Im trying to create:
Code (In Node/Mongoose/Express/Rest): https://github.com/1manStartup/Backbone-URLRoot
Live Example (on my ec2): http://54.251.104.185/
I believe my problem lies somewhere with the rendering of views and fetching of model data.
What Im Trying To Do: Render all Articles Unique to Dog. Route Is:
/api/makearticle/:id
If you don't use NodeJs, my JSON Api looks like this:
{
"articlename": "feed chocolate",
"_dog": {
"name": "pitbull",
"_id": "51d0b9ad6fd59c5059000002"
},
"_id": "51d0c22a6fd59c5059000007",
"__v": 0
},
{
"articlename": "took to vet",
"_dog": {
"name": "chihuaha",
"_id": "51d0b9af6fd59c5059000003"
},
"_id": "51d0c22e6fd59c5059000008",
"__v": 0
},
Here are my models and Collections:
Rest of backbone code found at:
https://github.com/1manStartup/Backbone-URLRoot
https://github.com/1manStartup/Backbone-URLRoot/blob/master/public/javascripts/demo-routerurl.js
Dog = Backbone.Model.extend({
idAttribute: '_id',
urlRoot:'/api/makedog' ,
initialize:function () {
this.dogs = new Dogs();
this.dogs.url = this.urlRoot + "/" + this.id ;
}
});
Dogs = Backbone.Collection.extend({
model: Dog,
url: '/api/makedog'
});
Article = Backbone.Model.extend({
idAttribute: '_id',
urlRoot:'/api/makearticle' ,
initialize:function () {
this.merr = new Articles;
this.merr.url = this.urlRoot + "/" + this.id ;
}
});
Please Help ive been on this for several days. Thanks.
Your API doesn't seem RESTful, so you're probably causing yourself more trouble than necessary: Backbone expects a RESTful API by default.
In any case, you need to do something like
var Article = Backbone.Model.extend({
idAttribute: '_id'
});
var ArticleCollection = Backbone.Collection.extend({
model: Article
});
var Dog = Backbone.Model.extend({
idAttribute: '_id',
initialize:function () {
this.articles = new ArticleCollection({
url: "api/dogs/" + this.get('id');
});
}
});
Then, you can do (e.g.):
var doggy = new Dog({id: 51d0b9ad6fd59c5059000002});
doggy.articles.fetch();
var articlesForDoggy = doggy.articles;
As a side node, why are you creating a new collection of dogs each time you instanciate a new dog model instance?
Also to be noted: I would seriously rething your API design. If you're using different routes for creating models (which seems to be indicated by the 'make...' routes), you're going to have to write a whole bunch of code to get the Backbone persistence layer to work with your API.
In addition, this API doesn't really follow conventions: api/dogs/XXX shouldn't be returning a list of articles: it should be returning the dog instance with id XXX. Using a URL like api/dogs/XXX/articles would make a lot more sense for the list of articles associated with a dog.
Friendly advice: although the code above should get you on your way, you really should rethink how you're designing your API. Using a non-RESTful API with Backbone, coupled with non-standard naming conventions will basically guarantee you'll be entering a world of pain with your project.
I'm trying to build an application using backbone.js and backbone-relational.js on the frontend, with a RESTful api run by Pyramid/Cornice/SQLAlchmeny on the backend.
At this stage, I have two models, Client (basically businesses) and Asset (the assets that the businesses own) ... and eventually there will be a number of other models, for users, sites, etc. A simplified example of the two models:
Client:
id
name
Asset:
id
make
model
purchase_cost
client_id
Now, my backbone.js code is currently working fine when fetching the data from these models from the server; I have two list views, one that shows a list of all the clients, and another that shows a list of all the assets.
My problem now is that I when I click on one of the Clients, in the list of clients, I want it to then show a list of only the Assets that belong to that particular client. No problem with the server-side part of that, it's just a filter(), my question is, how do I make backbone.js send such a constraint when it requests the list of Assets?
(While I've used RelationalModel in the code below, I'm still learning it and haven't really worked out how to make use of it yet)
window.Asset = Backbone.RelationalModel.extend({
urlRoot:"/api/assets",
defaults:{
"id":null,
"make":null,
"model":null,
"purchase_cost":null,
},
relations: [{
type: Backbone.HasOne,
type: Backbone.HasOne,
key: 'client_id',
relatedModel: Client
}]
});
window.AssetCollection = Backbone.Collection.extend({
model: Asset,
url: "/api/assets"
});
window.Client = Backbone.RelationalModel.extend({
urlRoot:"/api/clients",
defaults:{
"id":null,
"name":null
}
});
window.ClientCollection = Backbone.Collection.extend({
model: Client,
url: "/api/clients"
});
I don't think I need to show any of the Views here.
In my router, I currently have a listClients function and a listAssets (see below) function, and I think I'll need to add a listAssetsforClient(clientid) function, but I'm not sure what I'm meant to do with the clientid so that backbone.js will send it to the server as a constraint when GETting the list of Assets. I presume that whatever needs to be done will be in the AssetCollection model, but I can't see anything in the Collection API that looks appropriate. There are methods that will do filtering on an already fetched list, but it seems inefficient to be fetching an entire list of assets (and there may eventually be thousands of them) when I only need a subset of them, and can get the server to filter instead.
listAssets: function() {
$('#header').html(new AssetHeaderView().render().el);
this.assetList = new AssetCollection();
var self = this;
this.assetList.fetch({
success:function () {
self.assetListView = new AssetListView({model:self.assetList});
$('#sidebar').html(self.assetListView.render().el);
if (self.requestedId) self.assetDetails(self.requestedId);
}
});
},
Ok, I have figured it out. The fetch() method has an optional 'data' parameter which can pass the constraint. So, my new function would be:
listAssetsforClient: function(id) {
$('#header').html(new AssetHeaderView().render().el);
this.assetList = new AssetCollection();
var self = this;
this.assetList.fetch({
data: { clientid: id },
success:function () {
self.assetListView = new AssetListView({model:self.assetList});
$('#sidebar').html(self.assetListView.render().el);
if (self.requestedId) self.assetDetails(self.requestedId);
}
});
},
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.