backbone Cannot read property 'push' of undefined - backbone.js

i'm working with Backbone and when I generate the view I have the error Cannot read property 'push' of undefined". The line of the error is "self.subViewsReservas.push(new ReservaView({" in the push.
ReservaCollectionView = Backbone.View.extend({
initialize: function () {
if (Session.get('authenticated') && Session.get('authenticated') !== false) {
this.paginacionVista = new PaginacionReservasView({
collection: this.collection,
el: '.paginacionReservas',
reservasPagina: 5,
});
this.buscadorVista = new BuscadorView({
el: 'div.buscador-reservas',
//Pasamos la colección oficinas ya que hará las veces del conjunto de oficinas retornadas por el servidor
collection: new OficinasCollection(oficinas),
});
}
else {
}
},
render: function () {
var self = this;
this.template = _.template($('#divReservaTpl').html(), {});
self.$('.contenedor-reservas').empty();
self.collection.each(function (reserva, index) {
self.$('.contenedor-reservas').append(self.template({'data': reserva.toJSON()}));
});
this.collection.each(function (reserva, index) {
this.subViewsReservas = [];
self.subViewsReservas.push(new ReservaView({
el: '#' + reserva.get('Idreserva'),
model: reserva
}));
});
this.collection.each(function (reserva, index) {
//Limite de la paginacion 5 limite arbitrario
if (index < 5) {
//Lo Marcamos como visible y actualiazamos la paginación
self.collection.get(reserva.get('Idreserva')).set({'Visibilidad': true});
}
});
this.paginacionVista.render();
return this;
},
});
AppView = Backbone.View.extend({
initialize : function(){
var self = this;
self.usu = new UsuarioModel();
self.usu.fetch({
success: function (model){
Session.fetch({
success : function (){
Session.set('nombre',model.get('Nombre'));
Session.set('apellidos',model.get('Apellidos'));
Session.set('puntos_club',model.get('Puntosclub'));
self.render();
}
});
self.sideBar = new SideBarView({
el : '.sidebar',
model: model
});
self.sideBar.markOption('mis-reservas');
AppView = Backbone.View.extend({
initialize : function(){
var self = this;
self.usu = new UsuarioModel();
self.usu.fetch({
success: function (model){
Session.fetch({
success : function (){
Session.set('nombre',model.get('Nombre'));
Session.set('apellidos',model.get('Apellidos'));
Session.set('puntos_club',model.get('Puntosclub'));
self.render();
}
});
self.sideBar = new SideBarView({
el : '.sidebar',
model: model
});
self.sideBar.markOption('mis-reservas');
},
error : function (){
document.location = '/mygoldcar/login';
}
});
this.listenTo(Session, 'change', self.update);
},
render : function(){
var self = this;
var reservas = new ReservasCollection();
reservas.fetch({
success: function (collection){
if ( typeof collection.models[0].get('error') == 'undefined' || !collection.models[0].get('error')) {
var listRes = new ReservaCollectionView({
el : '.reservas-list',
collection: collection
});
listRes.render();
var popoverModel = new Popover();
popoverModel.setData(collection.models[0].get('kilometraje_ilimitado'), collection.models[0].get('duracion'));
self.popover = new PopoverView({
el: 'body',
model: popoverModel
});
self.popover.establecerPopover();
}
else document.location = '/mygoldcar' + self.urlLang(lang) + '/mi-cuenta/#msg/1';
},
error: function () {
document.location = '/mygoldcar' + self.urlLang(lang) + '/mi-cuenta/#msg/1';
}
});
},
update: function() {
var self = this;
self.sideBar.update(Session.get('nombre'),Session.get('apellidos'),Session.get('puntos_club'));
self.$el.find('.nombre-usuario').text(Session.get('nombre'));
},
updatePoints: function() {
var self = this;
self.usu.fetch({
success: function (model){
Session.set('puntos_club',model.get('Puntosclub'));
}
});
}
}); },
error : function (){
document.location = '/mygoldcar/login';
}
});
this.listenTo(Session, 'change', self.update);
},
render : function(){
var self = this;
var reservas = new ReservasCollection();
reservas.fetch({
success: function (collection){
if ( typeof collection.models[0].get('error') == 'undefined' || !collection.models[0].get('error')) {
var listRes = new ReservaCollectionView({
el : '.reservas-list',
collection: collection
});
listRes.render();
var popoverModel = new Popover();
popoverModel.setData(collection.models[0].get('kilometraje_ilimitado'), collection.models[0].get('duracion'));
self.popover = new PopoverView({
el: 'body',
model: popoverModel
});
self.popover.establecerPopover();
}
else document.location = '/mygoldcar' + self.urlLang(lang) + '/mi-cuenta/#msg/1';
},
error: function () {
document.location = '/mygoldcar' + self.urlLang(lang) + '/mi-cuenta/#msg/1';
}
});
},
update: function() {
var self = this;
self.sideBar.update(Session.get('nombre'),Session.get('apellidos'),Session.get('puntos_club'));
self.$el.find('.nombre-usuario').text(Session.get('nombre'));
},
updatePoints: function() {
var self = this;
self.usu.fetch({
success: function (model){
Session.set('puntos_club',model.get('Puntosclub'));
}
});
}
});

Inside collection.each, this points to the collection. So the property subViewsReservas is added to it, not the view instance. When you try to access it like self.subViewsReservas.push, self points to the view instance, which doesn't have subViewsReservas property, hence the error.
Initializing an array inside each like you're doing isn't doing much since it'll be reset with each invocation of the callback.
You should be initializing it in the initialize method, which is the right place to initialize things, where this will correctly point to the view instance as shown below
initialize: function () {
this.subViewsReservas = [];
}
For some reason if you want the collection to reset everytime, you can change the context to view by passing it as second argument to each like:
this.collection.each(function (reserva, index) {
this.subViewsReservas = [];
self.subViewsReservas.push(new ReservaView({
el: '#' + reserva.get('Idreserva'),
model: reserva
}));
}, self); // <--- makes view the context of callback,
// both 'self' and 'this' will refer to view

Related

Why my simple view is not working

I have this JS code:
$(function() {
var LinkView = new Backbone.View.extend({
render: function() {
this.$el.html(this.model.get('text'));
}
});
var Link = Backbone.Model.extend({
text: 'message',
say: function() {
console.log(this.text);
}
});
var l = new Link();
l.say();
var v = new LinkView({model : l, el : 'body'});
v.render();
});
I am waiting to get 'message' on the browser, but get the error TypeError: r.apply is not a function in the console. Why and how can I fix it ?
Please paste this, new was the problem in View, also did slight modification. it works now..
$(function() {
var Link = Backbone.Model.extend({
defaults : {
text: 'default message'
},
say: function() {
console.log(this.get('text'));
}
});
var LinkView = Backbone.View.extend({
render : function() {
this.$el.html(this.model.get('text'));
}
});
var l = new Link({text:'custom text message'});
l.say();
var v = new LinkView({model : l, el : 'body'});
v.render();
});

Backbone remove from collection not working

var Wine = Backbone.Model.extend({
winename: "Charles Shaw"
})
var Wines = Backbone.Collection.extend({
Model: Wine
})
var divElement = Backbone.View.extend({
initialize: function () {
this.render();
},
tagName: "ul",
render: function () {
$("#div1").empty();
$("#div1").append("<ul id='ulList'></ul>"),
wines.each(function (model) {
$("#ulList").append("<li>" + model.winename + "</li>");
});
return this;
}
});
var wine1 = new Wine();
wine1.winename = "wine1";
var wines = new Wines();
wines.add(wine1);
var wine2 = new Wine();
wine2.winename = "wine2";
wines.add(wine2);
function changewinename(model, winename) {
this.winename = winename;
}
var d = new divElement(wines);
wines.on("add", addwinename);
wines.on("remove", removewinename);
function addwinename(model, winename) {
d.initialize();
}
function removewinename(model, winename) {
d.initialize();
}
function AddWine() {
var winename = $("#wineName").val();
var wineFromUI = new Wine();
wineFromUI.winename = winename;
wines.add(wineFromUI);
$("#wineName").val("");
}
function changewinename(model, winename) {
this.winename = winename;
}
function RemoveWine() {
var wineValue = $("#wineName").val();
var wine1 = new Wine();
wine1.on({ "change:winename": changewinename });
wine1.set({ winename: wineValue });
alert(wine1.winename);
wines.remove(wine1);
$("#wineName").val("");
}
Collection remove for a model isn't working. Add works fine.
you need to add a function inside your collection like this:
var Wines = Backbone.Collection.extend({
Model: Wine,
removeElement: function(elements, options) {
return this.remove(elements, options);
}
})
and call it like this in your view:
wines.removeElement(wine1);

BackboneJS - Cannot call method 'on' of undefined

I have this simple BackboneJS app and it keeps returning this error on adding new model to collection: Cannot call method 'on' of undefined. Can someone help me. I can't see the problem in here.I have my templates defined in index.html, and I am using Slim framework and NotORM.
(function(){
window.App =
{
Models:{},
Collections: {},
Views : {}
}
window.template = function(id)
{
return _.template( jQuery('#' + id).html());
}
App.Models.Party = Backbone.Model.extend({
});
App.Collections.Partys = Backbone.Collection.extend({
model: App.Models.Party,
url: "http://localhost/BackboneJS/vjezba6/server/index.php/task"
});
App.Views.Party = Backbone.View.extend({
tagName :"div",
className: "box shadow aktivan",
template: template("boxovi"),
initialize: function()
{
this.model.on('change', this.render, this);
},
events:{
"click .izbrisi" : "izbrisi"
},
render: function()
{
var template = this.template( this.model.toJSON() );
this.$el.html(template);
return this;
},
izbrisi: function()
{
this.model.destroy();
},
ukloni: function()
{
this.remove();
}
});
App.Views.Partys = Backbone.View.extend({
tagName:"div",
id: "nosac-boxova",
initialize: function()
{
},
render: function() {
this.collection.each(this.addOne, this);
return this;
},
addOne: function(party) {
var partyView = new App.Views.Party({ model: party });
this.$el.append(partyView.render().el);
}
});
App.Views.Dodaj = Backbone.View.extend({
tagName: "div",
template : template("dodajTemp"),
events:
{
'submit' : 'submit'
},
submit : function(e)
{
e.preventDefault();
console.log(e);
var nazivPolje = $(e.currentTarget).find(".naziv").val();
var tekstPolje = $(e.currentTarget).find(".lokal").val();
var noviParty = new App.Views.Party({naziv:nazivPolje, tekst: tekstPolje});
this.collection.create(noviParty);
},
initialize: function()
{
},
render: function()
{
var template = this.template();
this.$el.html(template);
return this;
}
});
/* var kolekcijaPartya = new App.Collections.Partys([
{
naziv:"Ovo je prvi naziv",
tekst: "Ovo je prvi tekst"
},
{
naziv:"Ovo je drugi naziv",
tekst: "Ovo je drugi tekst"
}
]);*/
var kolekcijaPartya = new App.Collections.Partys;
kolekcijaPartya.fetch({
success: function()
{
var partysView = new App.Views.Partys({collection:kolekcijaPartya});
$("#content").prepend(partysView.render().el);
$("div.box").slideAj();
var dodajView = new App.Views.Dodaj({collection: kolekcijaPartya});
$("div#sidebar-right").html(dodajView.render().el);
}
});
})();
var noviParty = new App.Views.Party({naziv:nazivPolje, tekst: tekstPolje});
this.collection.create(noviParty);
so you are trying to add a View to your collection?

Backbone/Marionette ItemView not rendering on model change

Already a couple of hours struggle trying to solve this...
Although the model gets fetched correctly and I can verify it as the view gets informed of the model's 'change' event, it just does not render.
At startup, the default model data ('Test Project'), is correctly displayed in the view, but after the model is refreshed, the view is not refreshed.
I tried to show a new view in the layout after model refresh but it did not change much...
Any idea or opinion about this ?
App.Project = function () {
var Project = {};
var ProjectModel = Backbone.Model.extend({
defaults:{
id: 0,
name: "Test Project",
intro: "",
desc: ""
},
initialize: function () {
// Flag fetch status to avoid multiple simultaneous calls
this.loading = false;
var self = this;
App.vent.on("project:display", function (_id) { self.fetchProject(_id); });
},
fetchProject: function (_id) {
if (this.loading)
return true;
this.loading = true;
var self = this;
var id = _id;
this.url = 'data.project_'+id+'.json';
this.fetch({
success: function (_data) {
self.loading = false;
},
error: function () {
self.loading = false;
}
});
}
});
Project.Details = new ProjectModel();
var Layout = Backbone.Marionette.Layout.extend({
template: "#project-layout",
regions: { details: "#project_details" }
});
Project.initializeLayout = function () {
Project.layout = new Layout();
App.content.show(App.Project.layout);
};
App.addInitializer(function () {
App.Project.initializeLayout();
});
Project.display = function () {
App.Project.Views.showDetails(Project.Details);
App.vent.trigger("project:display", 1);
}
return Project;
}();
App.Project.Views = function () {
var Views = {};
var DetailView = Backbone.Marionette.ItemView.extend({
template: "#project-details-template",
tagName: "div",
initialize: function () {
//this.listenTo(this.model, "change", this.render, this);
},
modelEvents: {
'change': "modelChanged"
},
modelChanged: function() {
console.log(this.model);
this.render();
}
});
Views.showDetails = function (_project) {
var projectView = new DetailView({model: _project});
App.Project.layout.details.show(projectView);
};
return Views;
}();
App.ProjectRouting = function () {
var ProjectRouting = {};
ProjectRouting.Router = Backbone.Marionette.AppRouter.extend({
initialize: function (_options) {
this.route('project/', "displayProject", _options.controller.display);
}
});
App.vent.on("project:display", function (_id) {
App.navigate("project/");
});
App.addInitializer(function (_options) {
ProjectRouting.router = new ProjectRouting.Router({
controller: App.Project
});
});
return ProjectRouting;
}();

Backbone.js pass variable from router to collection

How do I pass the name variable from the router to the FriendInfocollection? Anytime I browse to localhost/app/person/MyName console.log returns a 404 for localhost/slim/index.php/person/
Can someone point me in the right direction on sharing this variable with the collection so it uses the correct url?
<!DOCTYPE html>
<html>
<head>
<title>I have a back bone</title>
</head>
<body>
<button id="add-friend">Add Friend</button>
<button id='view-friends'>View Friends</button>
<ul id="friends-list">
</ul>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.8.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.3.3/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/0.9.2/backbone-min.js"></script>
<script>
Friend = Backbone.Model.extend({
name: null,
age: null,
});
FriendDetailModel = Backbone.Model.extend();
FriendInfoModel = Backbone.Model.extend({
name: null
});
FriendDetailCollection = Backbone.Collection.extend({
url: '../slim/index.php/people/',
model: FriendDetailModel
});
FriendInfoCollection = Backbone.Collection.extend({
model: FriendInfoModel,
url: '../slim/index.php/person/' + name,
});
Friends = Backbone.Collection.extend({
initialize: function(models, options) {
this.bind("add",options.view.addFriendLi);
}
});
AppView = Backbone.View.extend({
el: $("body"),
initialize: function() {
this.friends= new Friends(null, {view:this});
},
events: {
"click #add-friend": "showPrompt",
},
showPrompt: function () {
var friend_name = prompt("Who is your friend?");
var friend_age = prompt("What is your friends age?");
var friend_model = new Friend({name: friend_name, age: friend_age});
this.friends.add(friend_model);
},
addFriendLi: function(model) {
$("#friends-list").append("<li>" + model.get('name') + " " + model.get('age') + "</li>");
}
});
var appview = new AppView;
var people = new FriendDetailCollection;
var person = new FriendInfoCollection({name:'Sean'});
FriendView = Backbone.View.extend({
el: $("body"),
initialize: function() {
_.bindAll(this,'render');
this.collection.bind('reset', this.render);
},
events: {
"click #view-friends": "fetch_list",
},
render: function() {
var results = this.collection.toJSON();
$.each(results, function(key, value) {
var msg = results[key]['firstname'] + " " + results[key]['lastname'];
console.log(msg);
});
},
fetch_list: function() {
people.fetch({
success: function(data) {
//console.log("success");
}
});
}
});
FriendInfoView = Backbone.View.extend({
el: $("body"),
initialize: function(name) {
_.bindAll(this,'render');
this.collection.bind('reset', this.render);
},
render: function(name) {
var results = this.collection.toJSON();
$.each(results, function(key, value) {
var msg = results[key]['firstname'] + " " + results[key]['lastname'];
console.log(msg);
});
}
});
friendview = new FriendView({collection: people});
friendinfoview = new FriendInfoView({collection: person});
AppRouter = Backbone.Router.extend({
routes: {
"friends":"people",
"person/:name":"personDetail"
},
people: function() {
console.log('all the people');
people.fetch({
success: function(data) {
//console.log("success");
}
});
},
personDetail: function(name) {
person.fetch({
success: function(data) {
console.log("success");
}
});
console.log('one person named ' + name);
}
});
var approuter = new AppRouter;
Backbone.history.start();
</script>
</body>
</html>
You should define routers like this :
var AppRouter = Backbone.Router.extend({
routes: {
'name/:name' : 'getPerson'
},
getPerson: function(name) {
var callperson = new Person.Details({
name : name
});
}
Instantiate routes when dom ready
app_router = new AppRouter;
Now you can access the name like this on your view:
this.options.name
But you must define the options variable inside the initialize functions
initialize: function ( options )
And for sure you can set the model like this :
model.set('name', name)

Resources