Prevent Backbone collection reset - javascript

I am new to Backbone. I see this in every backbone app:
var List = Backbone.collection.extend({
model: model
});
var myList = new List();
I am a bit confused about this. This script is included in a page, and when the page is reloaded or opened again and again, it will keep instantiate new collection doesn't it?
Whenever I save some models into this collection, things are still fine. But when I start to reload the page or open the page again, it will instantiate new collection with the same name again and the collection becomes empty again.
Any suggestions to prevent this? I want collection keep the models even if reloaded.

Use myList.fetch() in your view to load data from your api resource.
Some more info at BB site
Edit:
You can save model by using Collection create
So first instantiate new collection, then use
Collection.create({
name: 'John'
});
You can observe your network log to see what was posted to the api.
For your example:
var List = Backbone.collection.extend({
model: model
});
var myList = new List();
myList.create({
name: 'John'
});

Related

Retrieve an item from Backbone with ID in URL (independent of collection / model)

I am looking to retrieve a specific piece of data from Backbone (I'm using the localStorage adapter, not a server). I can see the ID of the items by looking at inspector.
I want a way to click on any item in any view, regardless of the collection it is in, or if it's it's own model, or whatever, and pass it to a details template.
So, <span onclick="router.navigate('details/:id', {trigger: true});">Single Page</span> would be attached in certain places throughout the app. All items would create the URL with their own ID.
Is it possible to agnostically render a template with the data from that single model?
My router:
assetDetail: function () {
var assetId = router.current().params[0];
var assetModel = new app.Models.Show({
id: assetId
});
var assetDetailView = new app.Views.assetDetail({
model: assetModel
});
},
However, when I put console.log( this.model ); in my detail page's render function the data is in the right format, but everything is null (the model defaults).
Thank you for any help.
Update:
As long as I know the exact collection, I can do the following. I'm currently rewriting my app to be like this. However, it still would be great to know if you can do it without knowing the collection (just having the ID)
var assetId = router.current().params[0];
var collection = new app.Collections.Collection({});
collection.fetch();
var themodel = collection.get(assetId);
var assetDetailView = new app.Views.assetDetail({
model: themodel
});

Trouble fetching from multiple models in backbone

I'm working on an app in node.js using backbone and am having trouble understanding how to go about pulling in data from two models that are related to one another. In this case I have a model Users and a model Comments, and on the user view I want to show some of the user data as well as a list of the user's comments. I've tried doing a multiple fetch statement (not sure if this is the right direction), but it's only returning the data in an object array and not under the attributes object that backbone requires.
Here's the function from the backbone router that I'm trying to work with:
showUser: function(id) {
var user = new User({id: id});
var comments = new Comments({userId: id});
$.when(user.fetch(), comments.fetch())
.done(function(userdata, commentdata) {
window.showUserView = new showUserView({
model: userdata,
data: commentdata
});
});
What is the preferred method of pulling data from multiple models / collections in backbone?
There is many ways to accomplish this, but the best one (in my point of view) is :
Split your view into two views (UserView & UserCommentsView), in each view add this method :
initialize : function() {
this.model.bind('change', 'render');
}
After that, change your router as :
showUser: function(id) {
var user = new User({id: id});
var comments = new Comments({userId: id});
new UserView({ model: user });
new UserCommentsView({ model: comments });
user.fetch();
comments.fetch();
}

Backbone Collection get(id) method

I have one main home page in my application and another page for each post that can be accessed through a list displayed in the home page..
this is how my router looks like :
var AppRouter = Backbone.Router.extend({
initialize: function(){
this.model = new model();
this.collection = new collection();
},
routes: {
"" : "showForm",
"post/:id" : "showPost"
},
showPost: function(id){
var curmodel = this.collection.get(id);
var post = new postView({model:curmodel});
post.render();
$(".maincontainer").html(post.el);
},
showForm : function(){
var qcView = new qcV({model:this.model, collection:this.collection});
qcView.render()
$(".maincontainer").html(qcView.el);
}
});
this is what one of the links to the posts in this list looks like
<h2><a id= "<%=_id%>" href="#post/<%=_id%>"><%=name%></h2></a>
my first question is: Is it dangerous to link pages with a hash-based URL in this manner?
my second question is: I am having no problem navigating to a posts view if I click one of the links in my home page. I my url successfully changes to something like http://127.0.0.1:3000/#post/51ffdb93c29eb6cc17000034 and that specific post's view is rendered. However at that point if I refresh the page, or if I directly type http://127.0.0.1:3000/#post/51ffdb93c29eb6cc17000034to my URL bar the this.collection.get(id) method in my showPost method in the router returns undefined. Can anyone help me figure out why this is the case?
I checked couple times that my initialize method gets called both times, and my collection and model is created successfully
For #2, you are most likely not fetching the collection on the "post" route. Try fetching the collection (if it does not exist) and then call render. That should do the trick!
I think #Trunal's on the right path for the 2nd question. For the first, no, it's not "dangerous". You're not really doing anything different than you would with a classic server-side app, passing information to the server via GET to retrieve info. In my opinion, this should be the preferred approach to implementing routes (rather than attempting to trigger backbone.history.navigate manually, as it avoids all kinds of setup and eventing issues that might otherwise occur).

Newly saved Backbone model does not appear in collection after fetch

I am using backbone local storage and experiencing some weird behavior.
I have a Model and Collection that is defined, instantiated, and fetched:
MyModel = Backbone.Model.extend({
localStorage: new LocalStore('example-myModels')
//note: LocalStore = Backbone.LocalStore -> https://github.com/jeromegn/Backbone.localStorage
});
MyCollection = Backbone.Collection.extend({
model : MyModel,
localStorage: new LocalStore('example-myModels')
});
var myCollection = new MyCollection();
myCollection.fetch(...);
This collection is then displayed as a list to the user. The user is able to "add" an item to the collection which eventually results in this code:
var newModel = new MyModel();
newModel.save(newModelAttributes, {
success: function(newlySavedModel) {
myCollection.add(newlySavedModel);
}
);
At this point myCollection has the newly added model and I can see the record successfully created in my localStorage database:
Pre-save LocalStorage:
Post-save LocalStorage:
The next step after the user adds the record is to go back to the list, at which point the collection is fetched again:
myCollection.fetch();
Now myCollection no longer contains the new record. No matter how many times I fetch, the new record will not be retrieved - even though I can see it in my localStorage database. I have also tried creating a new instance of the Collection and fetching that but it yields the same results. If I reload the browser, the new record appears as expected. Anyone have any idea what is going on? I get the feeling I am missing something fundamental here...
A running example that reproduces the issue is available here: http://jsbin.com/iyorax/2/edit (make sure the console is visible and click "Run with JS")
Thanks in advance!
Your model and your collection need to share a reference to the same instance of LocalStore, whereas right now you are creating two different objects. To fix this, create the LocalStore object outside of either model or collection, and pass in a reference to it in the constructors of your Model and collection.
I have an application working with Backbone.localstorage and what works for me is I first add the model to the collection and then I call save to the model. like this.
var newModel = new MyModel();
myCollection.add(newModel)
newModel.save();
Im not 100% sure, but my reasoning is that, your model is saved, but your collection is not, and perhaps an index is not being updated and at the time that you call fetch you are getting the unupdated collection.
Hope that helps.
The only reason I can think of due to which the model is not present in the collection is because of Duplicated ID's
I don't see a IdAttribute defined on the model. That could be a problem sometimes.

Backbone.js modeling

I'm new to backbone.js, and trying to figure something out, I have the following objects currently:
A TodoItem model
A TodoItemView view
A TodoCollection collection
I add a bunch of TodoItems to the TodoCollection, which creates TodoItemViews for each, this renders a basic list of todo items. Now, when I click on a todo item, I want to open a new tab with all the data for that todo item, in a form (i.e, editable), and a Save button.
I'm trying to figure out how to model this.. should the TodoItemView have a click event which:
opens a tab and fills up all the info and somehow binds events
from that new tab to functions within it? (almost certainly wrong)
create a new EditableTodoItemView, whose render opens a new tab,
click on the TodoItemView creates a new EditableTodoItemView and then
forgets about it (better, I think)
I'm assuming the EditableTodoItemView should reference the original model, i.e, the TodoItem should be shared between EditableTodoItemView and TodoItemView. No new collection needs to be created, the EditableTodoItemView calls backbone.sync() when the user hits save.
Likewise, I assume that when I create a new TodoItem, I push it into the TodoCollection, which creates a TodoItemView for it and possibly automatically creates an EditableTodoItemView if the item is new (i.e, has default data).
Does this make sense? Anything else I should be thinking about?
The easiest way to switch between multiple views is a Backbone.Router. You can use it like this:
var TodoRouter = Backbone.Router.extend({
routes: {
"edit/:id": "edit", // matches http://yourapp.com/#edit/1234
".*": "index", // matches http://yourapp.com/#everything-else
},
edit: function(id) {
item = TodoCollection.get(id);
this.view = EditableTodoItemView({model: item});
$("#main").html(this.view.render().el);
},
index: function() {
//...
}
});
Then just run window.router = new TodoRouter; Backbone.history.start(); where you start the application. Make sure, your TodoCollection is fetched, before you run this. You can use TodoCollection.bind("reset", _.once(function(){Backbone.history.start()}));.

Categories