Backbone event shows cached model - javascript

I am new on backbone and using backbone with requirejs to make my first SPA.
When a user navigates to site.com/#report/1 an API call goes to site.com/app/report/1 and collects the data and renders the data in view page. Then, he goes to dashboard and navigates to site.com/#report/2 and another API call collects data of report 2 and displays as well. The problem is when I am using any event handler. In the view page, when anyone clicks on any event, in the callback it says that there is two JSON object saved as model. But it should be the second one only. The first report data also comes in console.log.
For your better understanding, I am giving the code of my router, model and view page.
Router
define([
'backbone',
'models/authlogin',
], function (Backbone, AuthloginModel) {
var AppRouter = Backbone.Router.extend({
routes: {
'': 'renderLoginPage',
'dashboard': 'renderDashBoard',
'report/:id': 'renderReportDetails',
'report/new': 'renderNewReportPage',
'members': 'renderMembersPage',
'member/:id': 'renderMemberPage',
'login': 'renderLoginPage',
'organization': 'renderOrganizationPage',
'programs': 'renderProgramsPage',
'program/:id': 'renderProgramPage',
'*path': 'errorpage'
},
errorpage: function () {
requirejs(['views/404', 'views/dashboard'], function (errorview, DashboardView) {
if ($('nav').length != 1) {
var authlogin = new AuthloginModel;
new DashboardView({model: authlogin});
}
new errorview;
});
},
renderLoginPage: function () {
requirejs(['models/auth', 'views/login'], function (AuthModel, LoginView) {
var auth = new AuthModel;
new LoginView({model: auth});
});
},
renderDashBoard: function () {
requirejs([
'collections/reports',
'views/reports',
'views/dashboard',
'../../javascript/main',
], function (ReportsCollection, ReportsView, DashboardView, MainJS) {
var authlogin = new AuthloginModel;
new DashboardView({model: authlogin});
var reports = new ReportsCollection;
reports.fetch({wait: true}).then(function () {
new ReportsView({collection: reports});
});
});
},
renderReportDetails: function (page) {
requirejs([
'models/reportdetails',
'views/reportdetails',
'views/dashboard'
], function (ReportDetailsModel, ReportdetailsView, DashboardView) {
var reportdetails = new ReportDetailsModel({id: page});
reportdetails.fetch().then(function () {
if ($('nav').length != 1) {
var authlogin = new AuthloginModel;
new DashboardView({model: authlogin});
}
;
new ReportdetailsView({model: reportdetails});
});
});
},
renderNewReportPage: function () {
requirejs([
'collections/newreports',
'views/reports',
'views/newreports',
'../../javascript/main',
], function (ReportsCollection, ReportsView, DashboardView, MainJS) {
})
},
renderMembersPage: function () {
requirejs([
"collections/members",
"collections/invitations",
"views/members",
'views/dashboard'
], function (MembersCollection, InvitationsCollection, MembersView, DashboardView) {
var members = new MembersCollection();
members.fetch().then(function () {
var invitations = new InvitationsCollection();
invitations.fetch().then(function () {
if ($('nav').length != 1) {
var authlogin = new AuthloginModel;
new DashboardView({model: authlogin});
}
new MembersView({collection: members, collection2: invitations});
});
});
});
},
renderOrganizationPage: function () {
requirejs([
'models/organization',
'models/orgMembers',
'views/organization',
'views/dashboard'
], function (OrgModel, OrgMembers, OrgView, DashboardView) {
var organization = new OrgModel();
var members = new OrgMembers();
organization.fetch().then(function () {
if ($('nav').length != 1) {
var authlogin = new AuthloginModel;
new DashboardView({model: authlogin});
}
members.fetch().then(function () {
new OrgView({model: organization, model2: members});
})
})
});
},
renderProgramsPage: function(){
requirejs([
'collections/programs',
'models/program',
'views/programs',
'views/program',
'views/dashboard'
],function(ProgramsCollection,ProgramsModel,ProgramsView,ProgramView,DashboardView){
var programscollection = new ProgramsCollection;
programscollection.fetch().then(function(){
if ($('nav').length != 1) {
var authlogin = new AuthloginModel;
new DashboardView({model: authlogin});
}
new ProgramsView({collection: programscollection});
});
});
}
});
var initialize = function () {
var app_router = new AppRouter;
Backbone.history.start();
};
return {
initialize: initialize
};
});
Model
define([
'underscore',
'backbone'
],function(_,Backbone){
var ReportDetailsModel = Backbone.Model.extend({
urlRoot: '/app/report/',
idAttribute: 'id'
});
return ReportDetailsModel;
});
View
define([
'backbone',
'../../javascript/magnify_pop_up',
'text!templates/reportdetails.html',
'text!templates/reportcomments.html'
], function (Backbone, Magnify, ReportDetailsTemplate, RepCommentsTemplate) {
var ReportdetailsView = Backbone.View.extend({
el: '#container-2',
template: _.template(ReportDetailsTemplate),
initialize: function () {
this.render();
},
events: {
"click #reject": "reject",
"click #resolve": "resolve",
"click button.triage": "triage"
},
triage: function (e) {
e.preventDefault();
console.log(this.model.toJSON());
/* this.model.save({'status':1},{patch:true,success:function(model,response){
console.log('saved');
},error:function(model,response){
console.log('error');
}});*/
},
resolve: function (e) {
e.preventDefault();
this.model.save({'status':2},{patch:true});
},
reject: function (e) {
e.preventDefault();
this.model.save({'status':3},{patch:true});
},
render: function () {
$('#container').html(this.template(this.model.toJSON()));
this.$el.html(_.template(RepCommentsTemplate)(this.model.toJSON()));
return this;
}
});
return ReportdetailsView;
});

Related

Refresh Event in Backbone.js?

Is it possible to handle F5 button in Backbone? Something like:
events: {
'click .btn': 'function1'
}
Actually I have problem with destroying models after refresh. I get error, when the method get("title") is invoking. And this is App.js. And I thought to create new function after refresh event.
var App = (function () {
var api = {
Views: {},
Models: {},
Collections: {},
Content: null,
Router: null,
init: function () {
Backbone.history.start();
return this;
}
};
var ViewsFactory = {
view1: function () {
api.Models.Model1 = new Model1();
if (!this.View1) {
this.View1 = new api.Views.View1({
el: $(".content"),
model: api.Models.Model1
}).on("trigger1", function () {
api.Models.Model1 = this.model;
api.Router.navigate("#test", {trigger: true});
});
}
return this.View1;
},
view2: function () {
api.Collections.Collection1 = new Collection1();
var test = new Model2({
title: api.Models.Model1.get("title"),
collection: api.Collections.Collection1
});
return this.View2 = new api.Views.View2({
el: $(".content"),
model: test
});
}
};
var Router = Backbone.Router.extend({
routes: {
"": "view1",
"test": "view2"
},
view1: function () {
var view1 = ViewsFactory.view1();
view1.render();
},
view2: function () {
var view2 = ViewsFactory.view2();
view2.render();
}
});
api.Router = new Router();
return api;
})();
I handle this by router and "" route.

Cannot retrieve collection outside of the view

I'm making a simple list of people with option when clicking on person's name the Router will take a name as a parameter 'student/:name' and find a right person's object in a collection. I instantiate collection in a GroupView class by fetching it from the server. And that's where the Error appears: to get the access to collection (so I can find right object) in my viewStudent() method in Router class, I'm making one more instance of GroupView(), and console shows an error and that's right, 'cause there're no objects in collection.
I cannot wrap my head around this, why in GroupView() I receive data from the server and my collection just works fine, but second time I instantiate GroupView() in a Router - there's no collection? Maybe there's any other way I can get access to the collection in my Router? Any help would be greatly appreciated.
var StudentModel = Backbone.Model.extend({
defaults: {
name: 'Volodya',
lastName: 'Peterson',
age: 22,
gender: 'male'
}
});
var StudentsCollection = Backbone.Collection.extend({
model: StudentModel,
url: '/students.json'
});
var StudentView = Backbone.View.extend({
tagName: 'li',
template: _.template($('#studentTpl').html()),
events: {
'click': function () {
eventAggregator.trigger('student:selected', this.model);
}
},
render: function () {
this.$el.html(this.template(this.model.toJSON()));
return this;
}
});
var GroupView = Backbone.View.extend({
tagName: 'ul',
initialize: function () {
this.collection = new StudentsCollection();
this.collection.on('update', this.render, this);
this.collection.fetch();
},
render: function () {
var self = this;
this.collection.each(function (student) {
var studentView = new StudentView({
model: student
});
self.$el.append(studentView.render().el);
});
$('body').html(this.$el);
}
});
var RouterView = Backbone.View.extend({
tagName: 'ul',
render: function () {
var self = this;
_.each(this.model.toJSON(), function (value) {
self.$el.append('<li>' + value + '</li>');
});
return this;
}
});
var GroupController = function () {
this.start = function () {
var groupView = new GroupView();
};
};
var Router = Backbone.Router.extend({
routes: {
'': 'index',
'student/:name': 'viewStudent'
},
index: function () {
groupController.start();
},
viewStudent: function (name) {
var groupView = new GroupView();
var selectedStudent = groupView.collection.find(function (student) {
return student.get('name') === name;
});
$('body').append((new RouterView({ model : selectedStudent})).render().el);
}
});
var eventAggregator= _.extend({}, Backbone.Events),
groupController;
$(function () {
var router = new Router();
groupController = new GroupController();
Backbone.history.start();
eventAggregator.on('student:selected', function (student) {
var urlpath= 'student/'+ student.get('name');
router.navigate(urlpath, {trigger: true});
});
});

Backbone View: function is undefined

I want to build a simple backbone app for depositing and withdrawing funds via Stripe. Since a lot of the functionality is common, I placed that in a Stripe view, and extend the Deposit and Withdraw views from it, like so:
var App = {
Models: {},
Collections: {},
Views: {},
Router: {}
}
App.Views.Home = Backbone.View.extend({
el: $('#main-content'),
template: Handlebars.compile($('#home-template').html()),
render: function() {
this.$el.html(this.template())
return this
},
events: {
'click #deposit-button': 'navigateToDeposit',
'click #withdraw-button': 'navigateToWithdraw'
},
navigateToDeposit: function(e) {
Backbone.history.navigate('/deposit', true)
},
navigateToWithdraw: function(e) {
Backbone.history.navigate('/withdraw', true)
}
})
App.Views.Stripe = Backbone.View.extend({
el: $('#main-content'),
initialize: function() {
Stripe.setPublishableKey('pk_test_0QvQdPBkXAjB4EBsT4mf226x')
},
render: function() {
this.$el.html(this.template())
return this
},
events: {
'click #submit': 'submitForm'
},
submitForm: function(e) {
e.preventDefault()
$('#submit').prop('disabled', true)
var that = this
Stripe.card.createToken($('#form'), that.stripeResponseHandler)
},
stripeResponseHandler: function(status, response) {
var $form = $('#form')
if(response.error) {
$form.find('.payment-errors').text(response.error.message)
$('submit').prop('disabled', false)
} else {
console.log(this)
var form_data = this.getFormData(response.id),
that = this
$.post(that.transaction_endpoint, form_data, function(data, textStatus, jqXHR) {
Backbone.history.navigate('/home', true)
})
}
}
})
App.Views.Deposit = App.Views.Stripe.extend({
template: Handlebars.compile($('#deposit-template').html()),
getFormData: function(token) {
return {
amount: $('#form input[name=amount]').val(),
token: token
}
},
transaction_endpoint: 'handledeposit'
})
App.Views.Withdraw = App.Views.Stripe.extend({
template: Handlebars.compile($('#withdraw-template').html()),
getFormData: function(token) {
return {
name: $('#form input[name=name]').val(),
email: $('#form input[name=email]').val(),
token: token
}
},
transaction_endpoint: 'handlewithdraw'
})
App.Router = Backbone.Router.extend({
routes: {
'deposit' : 'showDepositView',
'withdraw' : 'showWithdrawView',
'*path' : 'showHomeView'
},
showDepositView: function() {
var depositView = new App.Views.Deposit()
depositView.render()
},
showWithdrawView: function() {
var withdrawView = new App.Views.Withdraw()
withdrawView.render()
},
showHomeView: function() {
var homeView = new App.Views.Home()
homeView.render()
}
})
var router = new App.Router()
Backbone.history.start()
The call to the getFormData method gives me an error saying the function is undefined, even though I have defined it in both Deposit and Withdraw views. Also, I added a console.log(this) right above it, and it logs the Window object to the console instead of the View. What am I doing wrong here?
I have a feeling it's to do with this call:
Stripe.card.createToken($('#form'), that.stripeResponseHandler)
Try binding this to the calling scope using .bind():
Stripe.card.createToken($('#form'), that.stripeResponseHandler.bind(this))
You don't really need to do var that = this but I'll leave it in for simplicity's sake.

Backbonejs usage of el

I've created 2 separate views, 1 to render the template and the other one is where I bind the events, then I tried merging them into one in which case it causes an Uncaught TypeError: Object [object Object] has no method 'template'. It renders the template and the events are working as well, but I get the error.
edit.js, this is the combined view, which I think it has something to do with their el where the error is coming from
window.EditView = Backbone.View.extend ({
events: {
"click #btn-save" : "submit"
},
initialize: function() {
this.render();
},
render: function() {
$(this.el).html(this.template());
return this;
},
submit: function () {
console.log('editing');
$.ajax({ ... });
return false;
}
});
var editView = new EditView();
signin.js, this is the view that I can't merge because of the el being used by the ajax call and in SigninView's $(this.el) which causes the rendering of the templates faulty
window.toSigninView = Backbone.View.extend ({
el: '#signin-container',
events: {
"click #btn-signin" : "submit"
},
initialize: function() {
console.log('Signin View');
},
submit: function() {
$.ajax({ ... });
return false;
}
});
var toSignin = new toSigninView();
window.SigninView = Backbone.View.extend({
initialize: function() {
this.render();
},
render: function() {
$(this.el).html(this.template());
return this;
}
});
and I use utils.js to call my templates
window.utils = {
loadTpl: function(views, callback) {
var deferreds = [];
$.each(views, function(index, view) {
if (window[view]) {
deferreds.push($.get('templates/' + view + '.html', function(data) {
window[view].prototype.template = _.template(data);
}));
} else {
alert(view + " not found");
}
});
$.when.apply(null, deferreds).done(callback);
}
};
In my Router.js, this is how I call the rendering of templates
editProfile: function() {
if (!this.editView) {
this.editView = new EditView();
}
$('#global-container').html(this.editView.el);
},
utils.loadTpl (['SigninView', 'EditView'],
function() {
appRouter = new AppRouter();
Backbone.history.start();
});
I think that I figured out your problem.
First merge your views and delete the line var toSignin = new toSigninView();
Second modify your utils.js code like this :
window[view].prototype.template = _.template(data);
new window[view]();

backbone view not being shown when page first rendered

I have the following set of Views and Router, when the page is first displayed the 'welcome' view navigated too in the 'initialize' method for the Router is not visible - the render method is called but the element is not updated. If navigate to another view (hashbang) and then navigate back I can then see the initial view.
Does anyone know what I'm doing wrong?
var AppRouter = Backbone.Router.extend({
contentView: null,
routes: {
'welcome': 'welcomeAction',
'settings': 'settingsAction',
'books': 'booksAction',
'book/:id': 'bookAction'
},
initialize: function () {
this.navigate('welcome', true);
},
welcomeAction: function () {
this.contentView = new views.WelcomeView({ 'model': new models.Welcome() });
},
settingsAction: function () {
this.contentView = new views.SettingsView({ 'model': new models.Settings() });
},
booksAction: function () {
this.contentView = new views.BooksView({ 'model': new models.Books() });
},
bookAction: function (id) {
this.contentView = new views.BookView({ 'model': new models.Book({ 'Id': id }) });
}
});
function App() {
this.router = null;
this.initialize = function () {
this.router = new AppRouter;
Backbone.history.start();
};
};
var reader = new App;
reader.initialize();
The View is shown below:
WelcomeView: Backbone.View.extend({
'el': '#content-pane',
tagName: 'div',
template: _.template(templates.welcome),
events: {
},
initialize: function () {
_.bindAll(this, 'render');
this.renderLoading();
this.model.fetch({ success: _.bind(function () {
this.model.set({ Date: new Date() });
this.render();
}, this)
});
},
renderLoading: function () {
var html = _.template(templates.loading)();
$(this.el).empty();
$(this.el).append(html);
},
render: function () {
var html = this.template({ date: this.model.get('Date') });
$(this.el).empty();
$(this.el).append(html);
}
}),
Seems like a $(document).ready issue to me. Are you sure all the content of your page (specifically #content-pane) is loaded before you create the view?

Categories