View with .fetch() not rendering - backbone.js

When I render this view
var MyView = Backbone.View.extend({
/* el : '.myview', used when rendered on router request */
render : function () {
var data = new Data(); /* a collection from ajax request */
var that = this;
data.fetch({
success : function (bla, data) {
var template = _.template( $('#temp').html(), {data: data.players} );
that.$el.html(template);
}
});
}
});
on router request, it works:
var Router = Backbone.Router.extend({
routes : {
'bla' : 'bla'
}
});
var myView = new MyView();
var router = new Router();
router.on('route:bla', function () {
myView.render();
});
But when I want it simply to load with the page, it doesn't:
var myView = new MyView({ el: $(".myview") });

Because in the last line you posted, you missing call to render function.
var myView = new MyView({ el: $(".myview") });
myView.render();
Besides of that, I see the workflow of initialization a bit wiered. Namely, requesting the data inside .render() function, that violates view single responsibility. Something, that I do in my applications.
var Router = Backbone.Router.extend({
routes : {
'bla' : 'bla'
},
bla: function () {
app.BlaApp();
}
});
app.BlaApp = function () {
var collection = new Collection();
collection.fetch({
success: function (collection) {
var view = new app.BlaView({model: collection});
view.render();
}
})
}
app.BlaView = Backbone.View.extend({
render: function () {
var template = // render template based on this.model;
this.$el.html(template);
return this;
}
});

Related

How to filter backbone collection to show tags

I'm creating a bookmarking tool that lets you create a list of stored bookmarks from an in-page form. The list will include an identifier tag (eg - Amazon www.amazone.com tag: shopping). From this created list, I want to also have a list showing the various tags that have been named.
This should probably use the filter method, but I cannot seem to get it to filter a correct list; I keep getting each tag listed for each URL created so there are multiple examples of the same tag.
Here is the code that correctly works in creating my form, the resulting URL list, and the module exports. This is from my Views js file:
var $ = require('jquery');
var Backbone = require('backbone');
var listTemplate = require('../../templates/addresslist.hbs');
var formTemplate = require('../../templates/addressform.hbs');
var detailTemplate = require('../../templates/addressdetail.hbs');
var AddressFormView = Backbone.View.extend({
tagName: 'form',
template: formTemplate,
events: {
'submit': 'addAddress'
},
render: function(){
var renderedHtml = this.template();
this.$el.html(renderedHtml);
return this;
},
addAddress: function(event){
event.preventDefault();
this.collection.create({
title: $('#title').val(),
url: $('#url').val(),
tag: $('#tag').val(),
});
$('#title').val('');
$('#url').val('');
$('#tag').val('');
},
});
var AddressListView = Backbone.View.extend({
tagName: 'ul',
initialize: function(){
this.listenTo(this.collection, 'add', this.renderItem);
},
render: function(){
return this;
},
renderItem: function(address){
console.log('address', address);
var addressItem = new AddressItemView({model: address});
this.$el.append(addressItem.render().el);
}
});
var AddressItemView = Backbone.View.extend({
tagName: 'li',
template: listTemplate,
render: function(){
var context = this.model.toJSON();
this.$el.html(this.template(context));
return this;
}
});
var AddressDetailView = Backbone.View.extend({
template: detailTemplate,
render: function(){
this.$el.html('').append(this.template);
return this;
}
});
module.exports = {
'AddressFormView': AddressFormView,
'AddressListView': AddressListView,
'AddressItemView': AddressItemView,
'AddressDetailView': AddressDetailView,
}
My router js file looks like this:
var $ = require('jquery');
var Backbone = require('backbone');
var views = require('./views/addressview');
var models = require('./models/address');
var Router = Backbone.Router.extend({
routes: {
'': 'index',
'detail/:id/': 'detail'
},
initialize: function(){
this.collection = new models.AddressCollection();
},
index: function(){
var addressForm = new views.AddressFormView({collection: this.collection});
$('.app').html(addressForm.render().el);
var addressListing = new views.AddressListView({collection: this.collection});
$('.app').append(addressListing.render().el);
this.collection.fetch();
},
detail: function(addressId){
this.collection.fetch().done(function(){
var address = this.collection.get(addressId);
var addressDetail = new views.AddressDetailView({model: address});
$('.app').html(addressDetail.render().el);
}.bind(this));
},
});
var router = new Router();
module.exports = router;
Create new event in view for multiple tag selection
tagSelected :function(event){
var tags = [<tag1>,<tag2>] //getting from multiple tag selection
var models = _.filter(this.collection.models,function(model){
return tags.indexOf(model.get('tag')) >= 0;
})
this.collection.reset(models);
this.render();
})

Adding model to a collection after save method in backbone

I am using the save method when my data is submitted. On success callback of the save method, the collection should be updated with the model which i have saved since i want to get the id of the model from my server. My code is as below
var app = app || {};
app.AllDoneView = Backbone.View.extend({
el: '#frmAddDone',
events:{
'click #addDone':'addDone'
},
addDone: function(e ) {
e.preventDefault();
var formData = {
doneHeading: this.$("#doneHeading").val(),
doneDescription: this.$("#doneDescription").val(),
};
var donemodel = new app.Done();
donemodel.save(formData,
{
success :function(data){
/*my problem is here how do i listen to collection event add that has been
instantiated in intialize property to call renderDone . My tried code is
var donecollection = new app.AllDone();
donecollection.add(donemodel);
and my response from server is
[{id:145, doneHeading:heading , doneDescription:description,
submission_date:2014-08-27 03:20:12}]
*/
},
error: function(data){
console.log('error');
},
});
},
initialize: function() {
this.collection = new app.AllDone();
this.collection.fetch({
error: function () {
console.log("error!!");
},
success: function (collection) {
console.log("no error");
}
});
this.listenTo( this.collection, 'add', this.renderDone );
},
renderDone: function( item ) {
var doneView = new app.DoneView({
model: item
});
this.$el.append( doneView.render().el );
}
});
Collection is
var app = app || {};
app.AllDone = Backbone.Collection.extend({
url: './api',
model: app.Done,
});
Model is
var app = app || {};
app.Done = Backbone.Model.extend({
url: "./insert_done",
});
View is
var app = app || {};
app.DoneView = Backbone.View.extend({
template: _.template( $( '#doneTemplate' ).html() ),
render: function() {
function
this.$el.html( this.template( this.model.attributes ) );
return this;
}
});
In your success callback you create an entirely new collection, which doesn't have any listeners registered. This is the reason why the renderDone isn't triggered.
The model you receive from the server should be added to the collection which is attached directly to your view, this.collection:
var self = this,
donemodel = new app.Done();
donemodel.save(formData, {
success :function(data){
// this is the collection you created in initialize
self.collection.add(donemodel);
},
error: function(data){
console.log('error');
}
});

How to delete a dependent model from the same collection in backbone.js

I have a model which has both navid and subnavid .While destroying a model i need to check in the entire collection , for other models which have navid as same as subnavid of the model i'am trying to delete . Please help me out . Thanks in advance . Heregoes my sample code.
Model:
var Node = Backbone.Model.extend({
defaults: {
NavId: '',
SubNavId: ''.
ItemName:''
} }
Collection:
var NodeCollection = Backbone.Collection.extend({ model:Node }
And i have two view one for the Node(i am building tr) and other for
the collection(I need to build table) var NodeCollectionView =
Backbone.View.extend({
initialize: function (options) {
var self = this; self.collection = new NodeCollection({ NavigationId: options.NavigationId });
self.collection.fetch({
success: function () {
/*I am getting hte proper collection from my restful api and iam able to bind it properly
self.render();
}
});
},
render: function () {
var that = this;
_.each(this.collection.models, function (item) {
that.RenderEachNode(item);
}, this);
},
RenderEachNode: function (item) {
var TempJsonNode = item.toJSON();
var self = this;
var nodeView = new NodeView({
tagName: 'tr',
id: 'NavId_' + TempJsonNode.NavItemId,
model: item
});
} });
var ItemTemplate = ""; ItemTemplate += " <td>"; ItemTemplate += " <a><%= ItemName %></a>"; ItemTemplate +=" </td>"; ItemTemplate
+=" <td>"; ItemTemplate +=" <a href='#' original-title='Delete ' class='tip_north Delete'>X</a>"; ItemTemplate +=" </td> ";
var NavigationItemView = Backbone.View.extend({
template: ItemTemplate,
render: function () {
var self = this;
var tmpl = _.template(this.template);
this.$el.html(tmpl(this.model.toJSON()));
return this;
},
events: {
"click .Delete": "DeleteBtnClick"
},
DeleteBtnClick: function () {
var self = this;
self.model.destroy({
success: function (status, data) {
var RetData = JSON.parse(data);
if (RetData.Status == 'Success') {
$(self.el).remove()
}
},
error: function () {
alert('Error In Deleting The Record');
}
});
return false;
} });
I am able to build the table properly but while destroying a model , i am not figuring out a way to destroy the dependent models.My Api is restricted in such a way that i cannot get a nested json ( if so i would have done with backbone relation). so i need to figure out some way that the other models and views which has the NavId of the model am deleting.
Please help me out.
How about something like:
var NodeView = Backbone.View.extend({
initialize: function() {
//when the model gets destroyed, remove the view
this.listenTo(this.model, 'destroy', this.remove);
},
//..clip
DeleteBtnClick: function () {
var self = this;
var collection = self.model.collection;
var navId = self.model.get('NavId');
self.model.destroy({
success: function (status, data) {
var RetData = JSON.parse(data);
if (RetData.Status == 'Success') {
//if parent was part of a collection
if (collection) {
//find related models
var related = collection.filter(function (model) {
return model.get('SubNavId') === navId;
});
//call destroy for each related model.
var promises = _.invoke(related, 'destroy');
//optional: if you want to do something when all the children
//are destroyed:
$.when.apply($, promises).then(function () {
console.log('all destroyed');
});
}
}
},
error: function () {
console.log(arguments);
alert('Error In Deleting The Record');
}
});
return false;
}
});
Edit: JSFiddle here

Problems with passing model to view from local storage

During the initialize function of my app I would like to default to my search page and pass my LeagueCollection as the model.
I am encountering an issue where I can add a watch to this.searchResults in my App initialize and see models: Array[3] as expected,
but when the this.model.toJSON() in the view is called I get the error object has no method toJSON.
This code was working fine with a in memory collection and then I switched to using backbone.localstorage.js to store the app data locally.
So my question is: why is the model not populated in the view?
In my main.js I have
var AppRouter = Backbone.Router.extend({
routes: {
"": "list",
...
},
initialize: function () {
this.searchResults = new LeagueCollection();
this.searchPage = new SearchPage({
model: this.searchResults.fetch()
});
this.searchPage.render();
},
...
});
In my Search Page view
window.SearchPage = Backbone.View.extend({
initialize:function () {
this.template = _.template(tpl.get('search-page'));
},
render:function (eventName) {
var self = this;
$(this.el).html(this.template(this.model.toJSON()));
this.listView = new LeagueListView({el: $('ul', this.el), model: this.model});
this.listView.render();
return this;
},
...
});
The method collection.fetch doesn't return the collection -- it's asynchronous. What you probably want is to use its success callback:
this.searchResults = new LeagueCollection();
var self = this;
this.searchResults.fetch({
success: function(collection, response) {
self.searchPage = new SearchPage( { model: collection } );
self.searchPage.render();
}
});

How to insert results of fetch of model in a view

I've fetch() a model by a server and I want to render the results of fetch() with a view.
The results of fetch() is an array of objects (var risultati) and I want render this var risultati. I've tried but nothing works.
var AppRouter = Backbone.Router.extend({
routes: {
"": "list",
},
initialize: function () {},
list: function () {
var utente = new Person();
var risultati;
utente.fetch({
success: function (data) {
var ris = data.attributes;
var risultati = ris.results;
console.log(risultati); /* risultati contains array of object to render*/
}
});
this.page = new UserListView({
model: this.utente
});
$('body').append(this.page.$el);
}
});
You may be having problems because your call to render the view is occurring separate from your utente.fetch() call.
Since .fetch() is asynchronous, your view code will be executed before .fetch() has finished. You should add the view creation/rendering as part of the success function, or you should bind the change event that occurs when the model is updated to fire off a new function that contains your view creation.
You should separate your MVC logic... don't attach objects (collections I think) to a router route handler.
Assuming that you are trying to render a collection of person models, I suggest you use a model and view for the person and a collection and a view for handling the "array of objects" :
var Person = Backbone.Model.extend({
initialize : function(){
// initialize the view
this.view = new PersonView({model : this});
}
}),
PersonView = Backbonke.View.extend({
render : function(){
// render your person
}
}),
UserList = Backbone.Collection.extend({
model : Person,
initialize : function(){
this.view = new UserListView({
collection : this
});
},
update : function(){
var self = this;
this.fetch({
success: function (data) {
var ris = data.attributes;
var risultati = ris.results;
console.log(risultati); /* risultati contains array of object to render*/ self.view.render();
}
});
}
}),
UserListView = Backbone.View.extend({
render : function(){
this.collection.each(function(el,i){
el.view.render();
});
}
});
and then use it as :
var page = new UserList();
var AppRouter = Backbone.Router.extend({
routes: {
"": "list",
},
initialize: function () {},
list: function () {
page.update();
}
});
Hope this helps!

Resources