Object #<HTMLTableSectionElement> has no method 'append' in Backbone.js View self.el - backbone.js

Window.TableView = Backbone.View.extend({
initialize: function() {
},
tagName:"tbody",
render: function() {
var self=this;
console.log(self.el);//will log <tbody></tbody>self.el.append("<tr></tr>");
return self.el;
}
);
tbView=new TableView();
tbView.render();
If I build a new view, and call the render function; I'll get the error Uncaught TypeError: Object # has no method 'append' has no method 'append' ...Is there a way to get it work?
Thanks!

Backbone view.el is a reference to the raw DOM object, which has no method append. In order to manipulate the element using jQuery, you should use the cached jQuery selector property view.$el instead:
self.$el.append("<tr></tr>");

Related

Add to backbone collection in response to event

I'm getting started with backbone.js but have got stuck at this point: I want to get data from a websocket and add it to a collection.
I've started with the code from http://adrianmejia.com/blog/2012/09/11/backbone-dot-js-for-absolute-beginners-getting-started/ but when I try to add in the event handling I cant figure out how to access the collection from within the event.
var AppView = Backbone.View.extend({
// el - stands for element. Every view has a element associate in with HTML content will be rendered.
el: '#container',
template: _.template("<h3>Hello <%= who %></h3>"),
// It's the first function called when this view it's instantiated.
initialize: function(){
console.log(this.collection) //<-- this.collection is OK here
MyPubSub.on('message', function (evt) {
this.collection.add(evt.data) //<-- TypeError: this.collection is undefined
});
this.render();
},
// $el - it's a cached jQuery object (el), in which you can use jQuery functions to push content. Like the Hello World in this case.
render: function(){
this.$el.html(this.template({who: 'planet!'}));
}
});
function init()
{
var websocket = new WebSocket("ws://example.com:8088");
MyPubSub = $.extend({}, Backbone.Events);
websocket.onmessage = function(evt) {
console.log("message")
MyPubSub.trigger('message',evt)
};
var appView = new AppView({collection:new AlertCollection()});
}
window.addEventListener("load", init, false);
I'm a complete newbie at this so I suspect I've made some kind of basic error in scoping. Also open to other approaches to read a websocket steam into a backbone app.
In the initialize function, add var myCollection = this.collection; and use myCollection within the MyPubSub.on(....

Backbone.js - each method throw error, while loop the models

In my view - after I fetch the data from collection, I am trying to loop the models using "native" - each method, but I am getting an error:
Uncaught TypeError: Object [object Object] has no method 'each'
still I am able to convert my models to json objects..
console.log(models.toJSON()); // giving result
models.each(function(model){
console.log(model); // throw the error.. why..?
})
Here is the part of the view where I am consoling:
initialize:function(){
var that = this;
this.collection = headerCollection;
this.listenTo(this.collection, "add", this.addAll);
this.collection.fetch();
},
addAll:function(models){
models.each(function(model){
console.log(model);
})
console.log(models.toJSON());
},
What would be the issue?
If you look at the Catalog of events in docs, it says that arguments being passed to collection's add event handler are (model, collection, options), so model won't have each method with it. May be you can listen to reset event as the arguments being passed for that are (collection, options).
Then you should be able to do models.each in addAll method.
It does not look like the collection is passed to your addAll method as an actual collection but as an array?
What does console.log(typeof models) do?
If you bind the eventhandler to this you can access the collection that way.
initialize:function(){
var that = this;
this.collection = headerCollection;
this.collection.on("add", this.addAll, this);
this.collection.fetch();
},
addAll:function() {
this.collection.each(function(model){
console.log(model);
})
console.log(this.collection.toJSON());
},
I am not familiar with the listenTo method so I don't know what that does.

Rendering Handlebars template with Backbone

I have a Backbone view (see below) that I believe to be doing the right thing
Index = Backbone.View.extend({
render: function() {
var activities = new Activities();
activities.fetch();
var tpl = Handlebars.compile($("#activities-template").html());
$(this.el).html(tpl({activities: activities.toJSON()}));
return this;
}
});
If execute each line in the render() function with Chrome JS console I get the expected result with the element I pass in getting populated with the template output. However, when I run this using the following
var i = new Index({el: $("body")})
i.render()
"i.$el" is completely empty--the HTML is not getting rendered like it does in console. Any ideas why?
fetch is an AJAX call so there's no guarantee that activities.toJSON() will give you any data when you do this:
activities.fetch();
var tpl = Handlebars.compile($("#activities-template").html());
$(this.el).html(tpl({activities: activities.toJSON()}));
Executing the code in the console probably gives the AJAX call time to return with something before you try to use activities.
You should do two things:
Fix your template to do something sensible (such as show a loading... message of some sort) if activities is empty.
Attach your view's render to the collection's "reset" event:
initialize: function() {
// Or, more commonly, create the collection outside the view
// and say `new View({ collection: ... })`
this.collection = new Activities();
this.collection.on('reset', this.render, this);
this.collection.fetch();
},
render: function() {
var tpl = Handlebars.compile($("#activities-template").html());
this.$el.html(tpl({activities: this.collection.toJSON()}));
return this;
}
I also switched to this.$el, there's no need to $(this.el) when Backbone already gives you this.$el.

Backbone.js: retrieving a collection from the server in PHP

I'm having a look at Backbone.js, but I'm stuck. The code until now is as simple as is possible, but I seem not to get it. I use Firebug and this.moments in the render of MomentsView is an object, but all the methods from a collection don't work (ie this.moments.get(1) doesn't work).
The code:
var Moment = Backbone.Model.extend({
});
var Moments = Backbone.Collection.extend({
model: Moment,
url: 'moments',
initialize: function() {
this.fetch();
}
});
var MomentsView = Backbone.View.extend({
el: $('body'),
initialize: function() {
_.bindAll(this, 'render');
this.moments = new Moments();
},
render: function() {
_.each(this.moments, function(moment) {
console.log(moment.get('id'));
});
return this;
}
})
var momentsview = new MomentsView();
momentsview.render();
The (dummy) response from te server:
[{"id":"1","title":"this is the moment","description":"another descr","day":"12"},{"id":"2","title":"this is the mament","description":"onother dascr","day":"14"}]
The object has two models according to the DOM in Firebug, but the methods do not work. Does anybode have an idea how to get the collection to work in the view?
The problem here is that you're fetching the data asynchronously when you initialize the MomentsView view, but you're calling momentsview.render() synchronously, right away. The data you're expecting hasn't come back from the server yet, so you'll run into problems. I believe this will work if you call render in a callback to be executed once fetch() is complete.
Also, I don't think you can call _.each(this.moments) - to iterate over a collection, use this.moments.each().
Try removing the '()' when instantiate the collection.
this.moments = new Moments;
Also, as it's an asynchronous call, bind the collection's 'change' event with the rendering.
I hope it helps you.

Backbone.js el is not working

App.Views.VideoView = Backbone.View.extend({
initialize: function() {
_.bindAll(this, 'render');
this.model = this.options.model;
this.render();
},
render: function() {
JST.video({
model: this.model
});
return this;
}
});
App.Views.PlayListView = Backbone.View.extend({
el: $("#playlistWrapper"),
initialize: function(videos) {
_.bindAll(this, 'render');
this.modelViews = $.map(videos.models, function(model, i) {
return new App.Views.VideoView({
model: model
});
})
this.render();
},
render: function() {
var that = this;
$(this.el).clear();
$.each(this.modelViews, function(i, modelView) {
$(that).el.append(modelView.render().el);
});
return this;
}
});
i am always getting below error
$(this.el).clear is not a function
[Break On This Error] $(this.el).clear();
it seems my el of PlayerListView is empty.
i have div with id playlistWrapper.
if i use jquery selector for playlistWrapper it gives proper element.
what am i doing wrong.
I'm a little late to the party on this, but the problem is that you're specifying a jquery selector before the DOM is loaded.
A backbone object is defined with an object literal passed in to the extend method. For example, the following are functionally the same:
MyView = Backbone.View.extend({
el: "#foo"
});
var viewObj = {el: "#foo"};
MyView2 = Backbone.View.extend(viewObj);
values on the right-hand side of a key/value pair in an object literal are parsed and executed immediately. this means that a jQuery selector used for el will be parsed as soon as you declare it, not when the view is instantiated. chances are, you have your javascript file included in your app and it's being downloaded before the DOM is loaded, so the jquery selector can't find the element you're referring to.
There are a number of things you can do to work around this.
you can call $(this.el) whenever you need to use the element
you can set this.el in the view initializer
you can set {el: $("#whatever")} as a parameter to the view constructor, assuming the view is constructed after the DOM has loaded
you can use the javascript module pattern to defer definition of the views and other backbone objects until after the DOM is loaded
and probably a handful of other options that i'm not thinking of at the moment
Well clear is not a jQuery function... You might be looking for empty?
Comments on your code:
In you video view:
no need to assign the model from the options, this is done for you
you might want to append the result of the templating (JST) to this.el otherwise nothing will show up...
In your playlist view:
in your render, in your each loop, change $(that).el to $(that.el)
since you define el as a jQuery, you do not need to use $(this.el) over and over
use this.$el.clear();
and update jquery.js file like
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"> </script>
and first Bind Initialize then el: bind.

Resources