I may be missing something simple here but I can't seem to find the answer I'm looking for.
I'm writing the front end for a cart in CoffeeScript using Backbone and while the server REST api is being completed I'm trying to use the localStorage adapter.
Basically in my application entry I want to grab the cart if it exists, otherwise create a new one.
I know I can grab the JSON from the localStorage but how can I fetch it as a Cart model on page load?
I basically want something like this (with the cart.get(1) being what I need)
# entry point
$ ->
cart = cart.get(1) || new Cart123.Cart id: 1
new Cart123.CheckoutView model: cart
# model
class Cart123.Cart extends Backbone.Model
localStorage: new Store 'Cart'
defaults: ->
State: new Cart123.State
Instances: new Cart123.Instances [ new Cart123.Instance ]
I'm assuming I don't need a cart collection because there's always only going to be one cart but as far as I know a collection is the only way to grab a model by ID.
Thanks for any pointers
If you've got the JSON for the model, the only thing you have to do is instantiate the Backbone model and pass the JSON. The JSON will be vivified into an actual model representing the data:
cart = new Cart800.Cart(cart.get(1) || id: 1)
new Cart800.CheckoutView model: cart
Related
I am currently fiddeling around with restangular and ui-router.
I do resolve a collection of items in my router which makes it available to the underlying controllers. I have a list of todos and i want to edit a todo. So i load a view where i can edit the item.
I get the model by $scope.todo = todos.get(id) I make a change to it and then i do $scope.todo.save() which updates the model on the server. But now i have the old item still in the collection of todos.
I want my collection to reflect the changes in the single item. I could delete the item from the collection and reinsert it afterwards, but this seems a little bit too complicated. Is there no easy way to update a model within a collection?
Update: Adding some Code
Note: The todos property gets resolved if the state is called.
If i edit a single todo i resolve it by
resolve : {
todo : function($stateParams, todos) {
return todos.get($stateParams.id);
}
}
I do some changes and then i call todo.save(). No changes will happen on the collection this way. I tried to do a todos.patch(todo) but that actually did a request to weird url and i guess it is intended to patch the whole collection (?)
I am sure there is a way to change a model within a collection, but i dont know how
After trying some stuff i ended up with replacing the item inside the collection. I created a little helper to lodash which i want to show here:
var replaceItemById = function(list, element) {
var index = _.indexOf(list, _.find(list, { id : element.id }));
list.splice(index, 1 , element);
return list;
};
_.mixin({'replaceItemById' : replaceItemById});
When i want to update a model inside a collection i do step by step:
Fetch the collection
Get a single item from the collection and edit it
Call save on the item
//The server returns the updated model
todo.save().then(function(editedTodo) {
_.replaceItemById(todos, editedTodo);
$state.go('todos.index');
});
This way i do not need to fetch the collection again (even if in most cases this is what you would do) and it is up to date after updating a single item.
I have fatched the data to Collection variable, but I am not sure what should I do next. How to use this data and to fill the template with it? Here is my code from the render function inside the View.
Collection.url = "../data";
Collection.fetch();
var compiled = _.template(self.data);
self.$el.prepend(compiled(/*MY JSON SHOULD GO HERE*/));
I am a newbie to backbone, so every help is appreaciated.
Here is a Collection definition:
var MainCollection = Backbone.Collection.extend({
model: MainModel,
//localStorage: new Backbone.LocalStorage("kitchen"),
initialize: function (models,options) { }
}), Collection = new MainCollection;
Here is a log of Collection and Collection coverted to JSON:
Assuming Collection is your collection's name (that's pretty confusing I have to say), this is what you're looking for:
self.$el.prepend(compiled(Collection.toJSON()));
Edit:
Don't forget you're fetching the data asynchronously. So when you're evaluating your template, the data hasn't come back yet, and your collection's still empty. Listen to the end of the request ('sync' event I think) or some other events so you know when the collection's populated OR use the success option of the fetch method to specify a callback :)
As for your logs. When you log an object, it will be automatically updated until you check the details. So you logged it while it was empty, but checked it after it was populated (a few ms afterwards).
I have the following Backbone.js collection:
var Tags = Backbone.Collection.extend({
url: "/api/v1/tags/"
}),
How do I update one of the models in the collection so that it posts to /api/v1/tags/id and saves the data for that model.
So if I change name of model with id 2 in the collection
It should PUT to
/api/v1/tags/2 with the following data:
name: new name id: 2
I've also recently wanted to update particular model in the collection. The problem was that if I did use just model.save it didn't update the collection. The goal was to change the model in collection, change it on the server, update collection accordingly and not use the sync method. So for example I have my variable collection and I want to change the model with id = 2. So the first thing, I will create an instance model, like this: var model = collection.get(2)Then I will update the attributes on this particular model:model.set({name: 'new name'})Then I will save it to the server:model.save({}, {url:'/api/v1/tags/'+model.get('id')})Then we have to update collection accordingly to the changes:collection.set({model},{remove: false})set method - it's a 'smart' update of the collection with the list of the models you passed in parameters. remove: false parameter - it's a restriction for a collection to remove existing models in collection. More here.
The first thing you can miss is that in your corresponding Tag model you'll need to set "urlRoot" to match the Collection's "url". Otherwise it doesn't know about the collection at all:
var Tag = Backbone.Model.extend({
urlRoot: "/api/v1/tags"
});
var Tags = Backbone.Collection.Extend({
model: Tag,
url: "/api/v1/tags"
});
This is useful if you want to save the tag separately:
var tag = collection.get(2);
tag.set({key: "something"});
tag.save(); // model.save works because you set "urlRoot"
On the collection, "create()" is also "update()" if id is not null. That's not confusing. :) Therefore, this is pretty much equivalent to the previous sample:
collection.create({id: 2; key: "something"});
This will update the existing tag with id=2 and then trigger a PUT.
This is an ancient question; answering because I was searching for the same answer--you've probably long since solved this problem and moved on. :)
You can pass variables to the save method. It accepts all the options which jQuery's ajax method uses (unless you overrided Backbone.Sync)
You could do something like:
model.save( { name:'new name' } );
The id and PUT method will automatically be added by Backbone for you.
I retrieve a list of models from server into a collection. When a user is interested in a specific model, I route it to a viewer for that model based on the id.
Now, let's say a user need edits to that model in the view - eg: he updates his name. I set the url of the model, update the name and call save. It calls the backend (Jersey in my case) and it gets saved. However, the collection is still not updated automatically.
Why cannot a collection bind to each change in the model and update it self?
What is the correct way of saving a model which is a part of the collection? Is it right to call save on a model (by setting its url) and then remove from its parent collection and then add it again with silent:true?
Thanks.
The Collection is not updated?
When you say "the collection is not updated automatically" I guess you mean "the View is not updated automatically".
The View will not respond to Model changes at least you say so explicitly using bindings:
// code simplified and no tested
var MyModel = Backbone.Model.extend({});
var MyModelView =
Backbone.View.extend({
initialize: function(){
this.model.on( "change:all", this.render, this );
},
render: function(){
this.$el.html( "<h1>" + this.model.title + "</h1>" );
}
})
Declare the URL explicitly for each Model
As #OlliM has said, this shouldn't be necessary if your backend is supporting an standard CRUD API. You can declare the URL in your Collection like this:
/app/collection
And Backbone will use this URLs as the API:
(GET) /app/collection fetch the whole Collection
(GET) /app/collection/1 fetch only the Model with id = 1
(PUT) /app/collection/1 update the Model with id = 1
(POST) /app/collection create a new Model
... DELETE and so on
Currently I'm doing a local Backbone app. And I want to know how to save data, specifically, how to construct the url attribute for Collection and Model. I have created a folder called data which is intended to hold the data. But how is the data structured? Is it just a single json file to hold the whole Collection data in it? Or it has many seprate json files to hold each Model's data individually? If it's a single json file, how should I created the url atrributes for both Collection and Model? If they are many separate json files, What should I do?
It is upto you :) . Backbone.Js models, collections work and can be made to work with pretty much any type of data source that expose through HTTP and URL. But it was designed to work against REST based services out of the box. Since you are interested to test the library and learning it i will advice you to stick to static JSON file or even Twitter timeline service.
Since all collections are in single JSOn file you will need just to set the URl for the collection.
View that renders the collection will instantiate the models and render them from the collection
Application
window["Application"] = {};
Application.Model = {};
Application.Collection = {};
Application.Views = {};
Application.Templates = {};
Application.Router = {};
Collection from url
Application.Collection.TimeLine = Backbone.Collection.extend({
url:"data/collection.json"
});
Current Url is http://localhost/timelineapp/index.html
Collection.Fetch will make GET request to http://localhost/timelineapp/data/collection.json
is this not clear enough i will add more detail