I have a backbone app where the user clicks a button and the a modal is displayed.
On closing the modal I do the following,
$('#myModal').on('hidden.bs.modal', function () {
self.remove();
App.Routes.Application.navigate(App.Routes.Application.previous(), { trigger: true } );
});
The problem is that the modal view is not getting removed, so I click the button to trigger it again, I see 2 modal windows, how can I remove the modal view and then navigate to the route I need?
I have tried ,
$('#myModal').on('hidden.bs.modal', function () {
setTimeout(function() {
self.remove();
}, 500);
App.Routes.Application.navigate(App.Routes.Application.previous(), { trigger: true } );
});
I thought maybe adding a delay between the removal and the navigate would work but nope.
Self is an instance of this view,
App.Views.CreateNewOrganisationView = Backbone.View.extend({
className: 'modal-body',
template: _.template( $('#tpl-new-organisation').html() ),
events: {
"submit .create-organisation" : "createOrganisation",
"click .js-add-member" : "addMember",
"click .js-add-client" : "addClient",
"click .js-add-project" : "addProject",
"click .js-add-team" : "addTeam",
"click .search-results a" : "selectSearchResult",
},
initialize: function() {
this.model = new App.Models.Organisation;
this.render();
},
clean: function() {
console.log("here");
},
render: function() {
//Backbone.Validation.bind(this);
var self = this;
$('#myModal').on('hidden.bs.modal', function () {
setTimeout( function() {
self.remove();
}, 500);
Pops.Routes.Application.navigate(App.Routes.Application.previous(), { trigger: true } );
});
this.$el.html( this.template() ).insertAfter('.modal-header');
this.model.get('members').add(App.Session);
this.model.get('members').first().set({
id: Pops.Session.get('user_id'),
admin: 0
});
var organisationMembersView = new App.Views.GroupsMembersAdminViews({
collection: this.model.get('members')
});
$("#myModal").modal();
return this;
},
addMember: function(e) {
e.preventDefault();
var element = $(e.currentTarget);
this.$('.search').parent().children().show();
this.$('.search').first().remove();
//element.parent().children().hide();
var search = new App.Views.SearchView({
collection: new App.Collections.Users,
type : "users",
merge: false
});
element.parent().prepend(search.render().el);
},
addClient: function(e) {
e.preventDefault();
var element = $(e.currentTarget);
this.$('.search').parent().children().show();
this.$('.search').first().remove();
//element.parent().children().hide();
var search = new Pops.Views.SearchView({
collection: new Pops.Collections.Clients,
type : "clients",
merge: false
});
element.parent().prepend(search.render().el);
},
addProject: function(e) {
e.preventDefault();
var element = $(e.currentTarget);
this.$('.search').parent().children().show();
this.$('.search').first().remove();
//element.parent().children().hide();
var search = new App.Views.SearchView({
collection: new App.Collections.Projects,
type : "projects",
merge: false
});
element.parent().prepend(search.render().el);
},
addTeam: function(e) {
e.preventDefault();
var element = $(e.currentTarget);
this.$('.search').parent().children().show();
this.$('.search').first().remove();
//element.parent().children().hide();
var search = new App.Views.SearchView({
collection: new App.Collections.Teams,
type : "teams",
merge: false
});
element.parent().prepend(search.render().el);
},
selectSearchResult: function(e) {
e.preventDefault();
var element = $(e.currentTarget),
self = this;
switch( element.data('type')) {
case "organisation":
var organisation = new Pops.Models.Organisation({ id: element.data('id')});
organisation.fetch({
success: function() {
self.model.get('organisations').add(organisation);
}
});
break;
case "project":
var project = new App.Models.Project({ id: element.data('id')});
project.fetch({
success: function() {
self.model.get('projects').add(project);
console.log(self.model);
var model = self.model;
self.$('.search').hide();
self.$('button').show();
var projectsDetails = new App.Views.ProjectNamePillView({
model : project
});
self.$('.search').parent().append( projectsDetails.render().el );
self.$('.search').remove();
}
});
break;
// case "workflow":
// break;
case "user":
var member = new App.Models.User({ id: element.data('id')});
member.fetch({
success: function() {
self.model.get('members').add(member);
console.log(self.model);
var model = self.model;
self.$('.search').hide();
self.$('button').show();
var personAvatar = new App.Views.UserInitialsWithAdmin({
model: member
});
self.$('.search').parent().append( personAvatar.render().el);
self.$('.search').remove();
}
});
break;
case "client":
var client = new App.Models.Client({ id: element.data('id')});
client.fetch({
success: function() {
self.model.get('clients').add(client);
var model = self.model;
self.$('.search').hide()
self.$('button').show();
var clientDetails = new App.Views.GroupNameAndAdminsView({
model: client
});
self.$('.search').parent().append( clientDetails.render().el );
self.$('.search').remove();
}
});
break;
case "team":
var team = new App.Models.Team({ id: element.data('id')});
team.fetch({
success: function() {
self.model.get('teams').add(team);
var model = self.model;
self.$('.search').hide()
self.$('button').show();
team.initialize();
var teamDetails = new App.Views.GroupNameAndAdminsView({
model: team
});
self.$('.search').parent().append( teamDetails.render().el );
self.$('.search').remove();
}
});
break;
}
},
remove: function() {
return Backbone.View.prototype.remove.apply(this, arguments);
},
close: function() {
this.unbind();
this.remove();
},
createOrganisation: function(e) {
e.preventDefault();
var element = $(e.currentTarget);
var self = this;
var data = element.serializeJSON();
this.model.save(data, {
success: function() {
if(App.Collections.OrganisationCollection != undefined) {
App.Collections.OrganisationCollection.add(self.model);
}
if(App.Collections._MyOrganisations != undefined) {
App.Collections._MyOrganisations.add(self.model);
}
$("#myModal").modal('hide');
//App.Routes.Application.navigate('#organisations/' . self.model.get())
},
});
}
});
Related
I'm trying to create a module using Backbone.js, but I'm getting the error Javascript Error: Uncaught TypeError: autoAuth.View is not a constructor.
Auth.js.erb
(function(app, Auth){
var game = app.module('game');
Auth.View = Backbone.View.extend({
el: '.js-auth',
cssClass: 'auth',
events: {
'click .js-popup': 'popupLogin',
'click .js-login-with-email': 'emailLogin',
'click .js-tos-modal': 'tosModal',
'click .js-privacy-modal': 'privacyModal',
'click .js-auto-login': 'autoLogin'
},
template: Handlebars.compile(
<%= embed('../templates/auth.hbs').inspect %>
),
initialize: function() {
Handlebars.registerPartial('login-buttons',
<%= embed('../templates/login-buttons.hbs').inspect %>
);
},
render: function() {
_.extend(this.options, {
skipOnboarding: game.player.get('skip_onboarding'),
claimableIncentive: game.incentive.get('claimable'),
claimableAmount: game.incentive.get('amount'),
});
this.$el.addClass(this.cssClass);
this.$el.html(this.template(this.options));
growth.urlChangeNotification();
},
popupLogin: function(event) {
event.preventDefault();
event.stopPropagation();
this.validateLogin(_.partial(popupLogin, event));
},
emailLogin: function(event) {
this.validateLogin(_.partial(this.emailAuth, event));
},
autoLogin: function(event) {
this.validateLogin(_.partial(this.autoAuth, event));
},
validateLogin: function(callback) {
if (this.$el.find('#agree-to-tos').is(':checked')) {
callback();
} else {
this.$el.find('.js-tos-error').show();
}
},
emailAuth: function(view_option, value) {
var emailAuth = app.module('emailAuth');
var emailAuthView = new emailAuth.View;
if (_.isString(view_option)) {
emailAuthView.setViewOption(view_option);
if (view_option === 'reset') {
game.user.set('reset_password_token', value);
}
}
emailAuthView.openModal({
allowCancel: view_option !== 'reset'
});
emailAuthView.render();
},
autoAuth: function(view_option, value) {
var autoAuth = app.module('autoAuth');
var autoAuthView = new autoAuth.View;
if (_.isString(view_option)) {
autoAuthView.setViewOption(view_option);
}
autoAuthView.openModal({
allowCancel: view_option !== 'reset'
});
autoAuthView.render();
},
tosModal: function() {
var modal = new Backbone.BootstrapModal({
content: <%= embed('../templates/terms-of-service.hbs').inspect %>
}).open();
},
privacyModal: function() {
var modal = new Backbone.BootstrapModal({
content: <%= embed('../templates/privacy-policy.hbs').inspect %>
}).open();
}
});
})(app, app.module('auth'));
AutoAuth.js.erb
function(app, AutoAuth)(
var game = app.module('game');
AutoAuth.View = ModalView.extend({
view_modes: ['login'],
template: Handlebars.compile(
<%= embed('../templates/auto-auth.hbs').inspect %>
),
events: {
'submit #email-login': 'logIn',
'click #login': function() {
this.setViewOption('login');
this.render();
},
},
genericErrorMessage: 'Oops something went wrong! Please contact support.',
initialize: function(options) {
var self = this;
this.options = options || {};
this.setViewOption('login');
_.bindAl(this, 'login');
game.user.on({
signin_sucess: function(){
self.reloadPage();
},
signin_error: function(data) {
self.options.error = false;
self.setViewOption('login');
var error = 'Unable to sign in with the given email and password.';
if (data && data.error) { error = data.error; }
self.options.signin_error = error;
self.render();
},
})
},
setViewOption: function(view) {
var self = this;
_.each(self.view_modes, function(k) {
self.options[k] = false;
});
self.options[view] = true;
},
render: function(){
this.$el.html(this.template(this.options));
if (mobile) window.scrollTo(0, 1); // hack for modals on mobile
this.delegateEvents();
this.clearErrors();
var authPage = _.chain(this.options)
.pick(function(value, key) { return value; })
.keys()
.value()[0];
growth.urlChangeNotification();
},
logIn: function(e) {
e.preventDefault();
this.options.email = this.$('#login_email').val();
if (!validateEmail(this.options.email)) {
this.options.signin_error = 'Must enter a valid email address.';
this.render();
return;
}
game.user.signIn({
email: this.options.email,
password: this.$('#login_password').val(),
remember_me: true
});
},
reloadPage: function() {
window.location = window.location.href.substr(0, window.location.href.indexOf('#'));
}
});
})(app, app.module('authAuth'));
Do you have this error on the line with var autoAuthView = new autoAuth.View; ?
To create a new instance of autoAuth.View you need to do var autoAuthView = new autoAuth.View();.
autoAuth.View is the class, to call the contructor, and create a new instance, you need to call it with ().
I put the fetch url with deferred method and I expect it will only invoke the remote ajax request one time.
However, it calls three times when I load the page.
How could I fix it? Thanks
js scripts
var Comments = Backbone.Collection.extend({
model: Comment,
url: fetch_comments_url,
initialize: function() {
this.fetch({
success: this.fetchSuccess,
error: this.fetchError
});
this.deferred = new $.Deferred();
},
deferred: Function.constructor.prototype,
fetchSuccess: function(collection, response) {
collection.deferred.resolve();
},
fetchError: function(collection, response) {
throw new Error("Products fetch did get collection from API");
},
var comments = new Comments();
...
comments.deferred.done(function() {
commentView.render();
emptyCommentView.render();
});
compelte js scripts
var Comments = Backbone.Collection.extend({
model: Comment,
url: fetch_comments_url,
initialize: function() {
this.fetch({
success: this.fetchSuccess,
error: this.fetchError
});
this.deferred = new $.Deferred();
},
deferred: Function.constructor.prototype,
fetchSuccess: function(collection, response) {
collection.deferred.resolve();
},
fetchError: function(collection, response) {
throw new Error("Products fetch did get collection from API");
},
wellFormedComments: function () {
var MESSAGE_LIMIT_LENGTH = 80
var models = comments.select(function (model) {
var msg = model.get("message")
if (msg!=null) {
msg = msg.replace(/^\s+|\s+$/g, '')
if (msg.length >= MESSAGE_LIMIT_LENGTH) {
model.set("preview_message", msg.substr(0, MESSAGE_LIMIT_LENGTH/2));
} else{
};
return true
}
else{
return false
};
});
return new Comments(models);
},
emptyComments: function () {
var models = comments.select(function (model) {
var msg = model.get("message")
return false===_(msg).notBlank();
});
return new Comments(models);
}
});
var comments = new Comments();
var CommentView = Backbone.View.extend({
el: $("#comments_section"),
render: function() {
var notNullComments = comments.wellFormedComments();
if (notNullComments.length > 0) {
$("#dadasay_comments_plugin").show();
}
var html = commentsTmpl(notNullComments.toJSON());
$(this.el).append(html);
},
});
var EmptyCommentView = Backbone.View.extend({
el: $("#empty_comments_list"),
render: function() {
var source = $('#empty_comments_list_tmpl').html();
var emptyComments = comments.emptyComments();
var html = emptyCommentsTmpl(emptyComments.toJSON());
$(this.el).html(html);
},
});
var commentView = new CommentView({
collection: comments
});
var emptyCommentView = new EmptyCommentView({
collection: comments
});
comments.deferred.done(function() {
commentView.render();
emptyCommentView.render();
});
The problem is that your comments collection triggers fetch when initialized. It's methods wellFormedComments and emptyComments creates new comments collections so they triggers fetch as well.
You can fix this by manually triggering fetch when required, something like:
var Comments = Backbone.Collection.extend({
model: Comment,
url: fetch_comments_url,
wellFormedComments: function() {
var MESSAGE_LIMIT_LENGTH = 80
var models = this.select(function(model) {
var msg = model.get("message")
if (msg != null) {
msg = msg.replace(/^\s+|\s+$/g, '')
if (msg.length >= MESSAGE_LIMIT_LENGTH) {
model.set("preview_message", msg.substr(0, MESSAGE_LIMIT_LENGTH / 2));
} else {};
return true
} else {
return false
};
});
return new Comments(models);
},
emptyComments: function() {
var models = this.select(function(model) {
var msg = model.get("message")
return false === _(msg).notBlank();
});
return new Comments(models);
}
});
var CommentView = Backbone.View.extend({
el: $("#comments_section"),
render: function() {
var notNullComments = comments.wellFormedComments();
if (notNullComments.length > 0) {
$("#dadasay_comments_plugin").show();
}
var html = commentsTmpl(notNullComments.toJSON());
$(this.el).append(html);
},
});
var EmptyCommentView = Backbone.View.extend({
el: $("#empty_comments_list"),
render: function() {
var source = $('#empty_comments_list_tmpl').html();
var emptyComments = comments.emptyComments();
var html = emptyCommentsTmpl(emptyComments.toJSON());
$(this.el).html(html);
},
});
var comments = new Comments();
var commentView = new CommentView({
collection: comments
});
var emptyCommentView = new EmptyCommentView({
collection: comments
});
comments.fetch({ // <--------- Do this manually once
success: function() {
commentView.render();
emptyCommentView.render();
},
error: function() {}
});
I think you can better structure your code as shown below, hope the comments explain the changes
var Comments = Backbone.Collection.extend({
model: Comment,
url: fetch_comments_url,
wellFormedComments: function() {
var MESSAGE_LIMIT_LENGTH = 80
var models = this.select(function(model) {
var msg = model.get("message")
if (msg != null) {
msg = msg.replace(/^\s+|\s+$/g, '')
if (msg.length >= MESSAGE_LIMIT_LENGTH) {
model.set("preview_message", msg.substr(0, MESSAGE_LIMIT_LENGTH / 2));
}
return true
}
return false
});
return new Comments(models);
},
emptyComments: function() {
var models = this.select(function(model) {
var msg = model.get("message")
return false === _(msg).notBlank();
});
return new Comments(models);
}
});
var CommentView = Backbone.View.extend({
el: $("#comments_section"),
template: commentsTmpl, // template reference, better create it here
initialize: function() {
this.render(); // self rendering
},
render: function() {
if (this.collection.length) { // use this.collection to refer to view's collection rather than external variables
$("#dadasay_comments_plugin").show(); //This shouldn't be a global selection
}
var html = this.template(this.collection.toJSON());
this.$el.append(html);
//---^ use cached jQuery object rather than creating new one
},
});
var EmptyCommentView = Backbone.View.extend({
el: $("#empty_comments_list"),
template: emptyCommentsTmpl,
initialize: function() {
this.render();
},
render: function() {
var source = $('#empty_comments_list_tmpl').html(); // unused?
var html = this.template(this.collection.toJSON());
this.$el.html(html);
},
});
var comments = new Comments();
comments.fetch({ // <--------- Do this manually once
success: function(collection, response) {
//----------------^ comments collection, all comments
var commentView = new CommentView({
collection: collection.wellFormedComments() // pass the resuting collection
});
var emptyCommentView = new EmptyCommentView({
collection: collection.emptyComments() // pass the resuting collection
});
},
error: function() {}
});
I need to close the current region in the method onRender and display a different region. But after a run operator 'return' I see again the old region.
Please tell me what is my mistake.
ApplicationPageLayout = Backbone.Marionette.Layout.extend({
template: "#application-page-layout-template",
regions: {
footerRegion: "#footer",
navigationRegion: "#navigation",
contentRegion: "#content"
},
onRender: function() {
if (this.options.postName) {
var footerData = {};
switch (this.options.postName) {
case "Admin":
this.footerRegion.show(new AdminFooterView());
break;
case "Dispatcher":
this.footerRegion.show(new DispatcherFooterView());
break;
default:
debugger; // See current region.
MainApplication.mainRegion.show(new LoginPageLayout(), { preventDestroy: true });
debugger; // See new region LoginPageLayout.
return; // Again see old region.
}
}
}
});
Ishow all code:
/**
* Main javaScript file.
*/
MainApplication = new Backbone.Marionette.Application();
LoginPageLayout = Backbone.Marionette.Layout.extend({
template: "#login-page-layout-template",
regions: {
authorizationFormRegion: "#login-form-wrapper",
errorRegion: "#login-message-wrapper"
},
// Show login form.
onRender: function () {
this.loginFormView = new LoginFormView();
this.authorizationFormRegion.show(this.loginFormView);
},
events: {
"click #login-button": "login"
},
login: function () {
var httpParameters = {pin: this.loginFormView.ui.pinCodeField.val()};
var thisLayout = this;
$.ajax({
url: '../autorisation',
type: 'POST',
data: httpParameters,
success: function(data) {
if (data.isSuccessfully) {
MainApplication.mainRegion.show(new ApplicationPageLayout(data), { preventDestroy: true });
} else {
var textMessageModel = new Backbone.Model({
message: "Ошибка. Учетная запись не найдена."
});
var loginMessageView = new LoginMessageView({
model: textMessageModel
});
thisLayout.errorRegion.show(loginMessageView);
}
},
error: function(data) {
alert("Сервер временно недоступен.");
}
});
return false;
}
});
ApplicationPageLayout = Backbone.Marionette.Layout.extend({
template: "#application-page-layout-template",
regions: {
footerRegion: "#footer",
navigationRegion: "#navigation",
contentRegion: "#content"
},
onRender: function() {
if (this.options.postName) {
var footerData = {};
switch (this.options.postName) {
case "Диспетчер":
this.footerRegion.show(new DispatcherFooterView());
break;
case "Администратор":
footerData.title = "Панель aдминитратора";
break;
default:
this.close();
}
}
}
});
FooterView = Backbone.Marionette.ItemView.extend({
regions: {
staffLogo: "#staff-logo"
},
ui: {
staffLogo: "#staff-logo"
}
});
DispatcherFooterView = FooterView.extend({
template: "#dispatcher-footer-template",
events: {
"click #dispatcher-logo": "showAlerts"
}
});
LoginFormView = Backbone.Marionette.ItemView.extend({
template: "#login-form-template",
ui: {
loginButton: "#login-button",
pinCodeField: "#login-pin"
}
});
LoginMessageView = Backbone.Marionette.ItemView.extend({
template: "#login-message-template"
});
MainApplication.addInitializer(function(options) {
MainApplication.addRegions({
mainRegion: "#mainRegion"
});
MainApplication.mainRegion.show(new LoginPageLayout());
});
$(function() {
MainApplication.start();
});
I'm trying to store my models into local storage using backone.localStorage. Unfortunately nothing gets stored.
As for as I understand the collection needs only one line
localStorage: new Backbone.LocalStorage("days")
but that doesn't help. If I check the localStorage using Chrome dev tools nothing is stored.
This is my code:
// Filename: app.js
define([
'jquery',
'underscore',
'backbone',
'localStorage'
], function($, _, Backbone){
var initialize = function(){
(function ($) {
var Day = Backbone.Model.extend({
initialize: function() {
this.on("change", this.calculateWorkTime);
this.calculateWorkTime();
},
defaults: {
"date": new Date(),
"fromAm": 0,
"toAm": 0,
"fromPm": 0,
"toPm": 0,
"workTime": 0
},
isValidTime: function(n) {
return !isNaN(parseFloat(n)) && isFinite(n) && parseFloat(n)>0;
},
calculateWorkTime: function() {
var work = 0.0;
if (timeToFloat(this.get("fromAm")) < timeToFloat(this.get("toAm")) ) {
work += timeToFloat(this.get("toAm")) - timeToFloat(this.get("fromAm"));
}
if (timeToFloat(this.get("fromPm")) < timeToFloat(this.get("toPm")) ) {
work += timeToFloat(this.get("toPm")) - timeToFloat(this.get("fromPm"));
}
this.set("workTime", floatToTime(work));
}
});
var DayList = Backbone.Collection.extend({
model: Day,
localStorage: new Backbone.LocalStorage("days")
});
var DataRow = Backbone.View.extend({
tagName: "tr",
template: _.template($('#table-row-day').html()),
events: {
"change .edit-field": "updateModel",
"click #button-delete-day": "deleteDay"
},
initialize: function() {
this.listenTo(this.model, 'destroy', this.remove);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
updateModel: function(event) {
var myValue = "leer";
switch (event.currentTarget.id) {
case "table-edit-date":
myValue = this.$('#table-edit-date').val();
this.model.set("date", myValue);
break;
case "table-edit-fromAm":
myValue = this.$('#table-edit-fromAm').val();
this.model.set("fromAm", myValue);
break;
case "table-edit-toAm":
myValue = this.$('#table-edit-toAm').val();
this.model.set("toAm", myValue);
break;
case "table-edit-fromPm":
myValue = this.$('#table-edit-fromPm').val();
this.model.set("fromPm", myValue);
break;
case "table-edit-toPm":
myValue = this.$('#table-edit-toPm').val();
this.model.set("toPm", myValue);
break;
}
this.render();
console.log(this.model.toJSON());
},
deleteDay: function(a, b, c, d) {
this.model.destroy();
}
});
var Days = new DayList;
AppView = Backbone.View.extend({
el: $("body"),
initialize: function () {
this.listenTo(Days, 'add', this.addOne);
this.listenTo(Days, 'all', this.refreshTotal);
this.total = this.$("#total-work");
Days.fetch();
this.refreshTotal();
},
events: {
"click #button-add-day": "addDay"
},
addDay: function () {
var day = new Day({
"date": $("#form-add-date").val(),
"fromAm": $("#form-add-fromAm").val(),
"toAm": $("#form-add-toAm").val(),
"fromPm": $("#form-add-fromPm").val(),
"toPm": $("#form-add-toPm").val()
});
Days.add(day);
},
addOne: function(day) {
var view = new DataRow({model: day});
this.$("#table-body-days").append(view.render().el);
},
refreshTotal: function() {
var work = 0;
Days.each(function($i) {
work += timeToFloat($i.get("workTime"));
});
this.total.html(floatToTime(work));
}
});
function timeToFloat(time) {
var parts = time.split(":");
if (parts.length<2) return 0.0;
return parseFloat(parts[0])+parseFloat(parts[1])/60;
}
function floatToTime(floatValue) {
var fraction = floatValue - Math.floor(floatValue);
var whole = Math.floor(floatValue);
return whole+":"+Math.round(fraction*60.0);
}
var appview = new AppView;
})($);
};
return {
initialize: initialize
};
});
As the comment points out the calls to save are missing. I added them to DataRow.updateModel() and AppView.addDay().
This is the correct code:
// Filename: app.js
define([
'jquery',
'underscore',
'backbone',
'localStorage'
], function($, _, Backbone){
var initialize = function(){
(function ($) {
var Day = Backbone.Model.extend({
initialize: function() {
this.on("change", this.calculateWorkTime);
this.calculateWorkTime();
},
defaults: {
"date": new Date(),
"fromAm": 0,
"toAm": 0,
"fromPm": 0,
"toPm": 0,
"workTime": 0
},
isValidTime: function(n) {
return !isNaN(parseFloat(n)) && isFinite(n) && parseFloat(n)>0;
},
calculateWorkTime: function() {
var work = 0.0;
if (timeToFloat(this.get("fromAm")) < timeToFloat(this.get("toAm")) ) {
work += timeToFloat(this.get("toAm")) - timeToFloat(this.get("fromAm"));
}
if (timeToFloat(this.get("fromPm")) < timeToFloat(this.get("toPm")) ) {
work += timeToFloat(this.get("toPm")) - timeToFloat(this.get("fromPm"));
}
this.set("workTime", floatToTime(work));
}
});
var DayList = Backbone.Collection.extend({
model: Day,
localStorage: new Backbone.LocalStorage("days")
});
var DataRow = Backbone.View.extend({
tagName: "tr",
template: _.template($('#table-row-day').html()),
events: {
"change .edit-field": "updateModel",
"click #button-delete-day": "deleteDay"
},
initialize: function() {
this.listenTo(this.model, 'destroy', this.remove);
},
render: function() {
this.$el.html(this.template(this.model.toJSON()));
return this;
},
updateModel: function(event) {
var myValue = "leer";
switch (event.currentTarget.id) {
case "table-edit-date":
myValue = this.$('#table-edit-date').val();
this.model.set("date", myValue);
break;
case "table-edit-fromAm":
myValue = this.$('#table-edit-fromAm').val();
this.model.set("fromAm", myValue);
break;
case "table-edit-toAm":
myValue = this.$('#table-edit-toAm').val();
this.model.set("toAm", myValue);
break;
case "table-edit-fromPm":
myValue = this.$('#table-edit-fromPm').val();
this.model.set("fromPm", myValue);
break;
case "table-edit-toPm":
myValue = this.$('#table-edit-toPm').val();
this.model.set("toPm", myValue);
break;
}
this.model.save();
this.render();
console.log(this.model.toJSON());
},
deleteDay: function(a, b, c, d) {
this.model.destroy();
}
});
var Days = new DayList;
AppView = Backbone.View.extend({
el: $("body"),
initialize: function () {
this.listenTo(Days, 'add', this.addOne);
this.listenTo(Days, 'all', this.refreshTotal);
this.total = this.$("#total-work");
Days.fetch();
this.refreshTotal();
},
events: {
"click #button-add-day": "addDay"
},
addDay: function () {
var day = new Day({
"date": $("#form-add-date").val(),
"fromAm": $("#form-add-fromAm").val(),
"toAm": $("#form-add-toAm").val(),
"fromPm": $("#form-add-fromPm").val(),
"toPm": $("#form-add-toPm").val()
});
Days.add(day);
day.save();
},
addOne: function(day) {
var view = new DataRow({model: day});
this.$("#table-body-days").append(view.render().el);
},
refreshTotal: function() {
var work = 0;
Days.each(function($i) {
work += timeToFloat($i.get("workTime"));
});
this.total.html(floatToTime(work));
}
});
function timeToFloat(time) {
var parts = time.split(":");
if (parts.length<2) return 0.0;
return parseFloat(parts[0])+parseFloat(parts[1])/60;
}
function floatToTime(floatValue) {
var fraction = floatValue - Math.floor(floatValue);
var whole = Math.floor(floatValue);
return whole+":"+Math.round(fraction*60.0);
}
var appview = new AppView;
})($);
};
return {
initialize: initialize
};
});
I know Im pretty close to figuring this out. Im trying to filter out my collection based on if favorite eq true. If I console.log - I can see it's doing its job. But it's not updating my view.
Anyone have any idea what I'm missing or doing wrong?
Here is my code:
var Products = Backbone.Model.extend({
// Set default values.
defaults: {
favorite: false
}
});
var ProductListCollection = Backbone.Collection.extend({
model: Products,
url: '/js/data/wine_list.json',
parse: function(data) {
return data;
},
comparator: function(products) {
return products.get('Vintage');
},
favoritesFilter1: function(favorite) {
return this.filter(function(products) {
return products.get('favorite') == true;
});
},
favoritesFilter: function() {
return this.filter(function(products) {
return products.get('favorite') == true;
});
},
});
var products = new ProductListCollection();
var ProductListItemView = Backbone.View.extend({
el: '#wine-cellar-list',
initialize: function() {
products.bind('reset', this.render, this);
products.fetch();
this.render();
},
render: function() {
console.log(this.collection);
var source = $('#product-template').html();
var template = Handlebars.compile(source);
var html = template(this.collection.toJSON());
this.$el.html(html);
return this;
},
});
// Create instances of the views
var productView = new ProductListItemView({
collection: products
});
var CellarRouter = Backbone.Router.extend({
routes: {
'': 'default',
"favorites": "showFavorites",
"purchased": "showPurchased",
"top-rated": "showTopRated",
},
default: function() {
productView.render();
},
showFavorites: function() {
console.log('Favorites');
productView.initialize(products.favoritesFilter());
},
showPurchased: function() {
console.log('Purchased');
},
showTopRated: function() {
console.log('Top Rated');
}
});
$(function() {
var myCellarRouter = new CellarRouter();
Backbone.history.start();
});
There's many mistakes in your code, I'll try to clarify the most I can :
Your collection should be just like this :
var ProductListCollection = Backbone.Collection.extend({
model: Products,
url: '/js/data/wine_list.json',
comparator: 'Vintage' // I guess you want to sort by this field
});
Your view like this :
var ProductListItemView = Backbone.View.extend({
el: '#wine-cellar-list',
initialize: function() {
this.collection.bind('reset', this.full, this);
this.collection.fetch();
},
full: function() {
this.render(this.collection.models);
},
favorites: function(favorite) {
this.render(this.collection.where(favorite)); // here's the answer to your question
},
render: function(models) {
console.log(models);
var source = $('#product-template').html();
var template = Handlebars.compile(source);
var html = template(models.toJSON()); // You may have to change this line
this.$el.html(html);
return this;
},
});
And in your router :
showFavorites: function() {
console.log('Favorites');
productView.favorites(true); // or false, as you like
}