Mapping backbone events in a separate backbone class file - backbone.js

I'm using CoffeeScript with a Backbone view class. When I include the class in the same page as the html everything works fine. When I use a separate file and export the class, it initialises but the events aren't mapped.
The class file is:
root = exports ? this
class root.AppView extends Backbone.View
el: $("#app")
events:
'click #appBtn1' : 'handleEvent'
'click #appBtn2' : 'handleEvent'
initialize: =>
alert 'init'
handleEvent: =>
alert 'event'
Only the initialize function fires. What do I need to alter to map the events when the code is in a separate class?

The problem is that the function
$("#app")
runs immediately when you define the class. So when the class is in a separate file, the #app element doesn't (necessarily) exist in the DOM yet.
What you should be doing is using a selector string instead, which Backbone will pass to the $ function when the class is instantiated:
el: "#app"

Related

Trigger click event from one file from another in BackboneJS

in my project i am not able to trigger click event registered in one backbone view from another backbone view. its actually i am having a file type input placed hidden from the user and i need to trigger the file type input.
var FileView = Backbone.View.extend({
....
events : {
"click .delete-image" : "deleteFile",
}
....
});
var FilesView = Backbone.View.extend({
....
events : {
"click #attach" : "attachFile",
},
attachFile : function() {
this.fileView.trigger("click .delete-image");
}
....
});
but i tried like this the event is not get triggered. how is it possible.
the events hash attaches itself to the jquery element that represents the view, not the backbone view itself. So you would most likely have to do something like this:
attachFile : function() {
$('.delete-image', this.fileView.$el).trigger("click");
}
but I would discourage this kind of non-pattern and instead work towards using something we call an Event Aggregation pattern. You can find a collection of really good SO solutions next:
fire an event from one view to another in backbone
Backbone.js global events
Multiple view on same page with backbone.js

Backbone 0.9.2 view initialize not being called

I am new to Backbone.js. I am using CoffeScript on a v0.9.2 app. The app works "fine" but the initialize() method of the views is not being called. Events are not being properly binded either. I am trying to figure out why this is not the case. I am using other (manual) ways to bind events to elements but that should not be the case.
The app is instantiated with this:
window.Site =
Models: {}
Collections: {}
Views: {}
Routers: {}
init: ->
new Site.Routers.MyRouter()
Backbone.history.start()
$(document).ready ->
Site.init()
The router:
class Site.Routers.MyRouter extends Backbone.Router
routes:
'': 'index'
initialize: ->
# some code here (this IS being called)
index: =>
# this is also being called since I am trying mysite.com/
view = new Site.Views.MyView()
$('#someId').html(view.render().el)
The view:
class Site.Views.MyView extends Backbone.View
template: JST['views/index']
events:
'click .someElement': 'someMethod'
inititalize: ->
console.log "hello" # NOT CALLED
_.bindAll #
#
render: =>
# draw stuff (this works)
#
The view gets drawn fine. Why is initialize not being called?
Thanks!
You have to spell initialize correctly =p
inititalize: -> # should be `initialize: ->`
console.log "hello" # NOT CALLED
For future readers, also check you don't have two initialize functions.
Backbone.View.extend({
initialize: function () {
// not called
},
// stuff
initialize: function () {
// overwrites previous
}
})
I don't write CoffeeScript, but the only place I see an instance of your view initailized is in the router:
index: =>
view = new Site.Views.MyView()
I suspect the router's index is not being called and as a result your view's initialize isn't being called. Extending a view doesn't create an instance of the view, rather it creates a customized definition of a view.
HTH.

Backbone.js call method of view#1 from view#2

How can I call a method of View#1 from view#2 in backbone?
view#1 = Backbone.View.extend({
plot_markers:function(){
/*some code */
}
});
view#1 = Backbone.View.extend({
initialize:function(){
view#1.plot_markers();
}
});
How do i set global methods in backbone. where many view can use the same method
Thanking you
View#2 would have to have a reference to View#1, but that can be dangerous as it would be easy to create a circular reference. A better way of approaching this would be to have an intermediary, such as a controller do the method invocation. View#1 would trigger an event that the controller listens to, and in turn invoke the proper method on View#2 or vice-versa. The idea is to keep your views ignorant of each other, as this follows the whole idea of "separation of concerns."
You could have View2 extend View1
class View1 extends Backbone.View
plot_markers: -> # dot stuff
class View2 extends View1
initialize: ->
#plot_markers()
Depending on how your application is structured and how views relate to each other you can either 1) fire an event your router listens to and executes another action in response (like Brendan Delumpa suggested), or 2) create a global event aggregator that you can listen to anywhere and trigger events on anywhere.
Derick Bailey has written on how and when to use event aggregators in Backbone. Here's a simple example:
App = {};
App.events = _.extend({}, Backbone.Events);
// Subscribe to your:event
App.events.on("your:event", function(){
// Carry out whatever's supposed to happen when the event
// has been triggered here.
});
// Publish your:event
App.events.trigger("your:event");
try this,
view1 = Backbone.View.extend({
plot_markers:function(){
//add your code here,..
alert('called....');
}
});
view2 = Backbone.View.extend({
initialize:function(){
var v1 = new view1();
v1.plot_markers();
}
});
var v2 = new view2();

Representing existing HTML as Backbone.js data structures in CoffeeScript

I'm having a rough time wrapping my head around this.
I have an HTML list, and I want to use Backbone.js to handle events on those list items. Here's what I've got so far. This is a simplified scenario to help me better understand how to structure a larger application. For my example, I simply want to ingest an existing HTML list into the Backbone structure, and handle click events through the Backbone view.
I'm getting an error related to using #model in the view, but I'm fairly certain I'm misunderstanding things conceptually here.
CoffeeScript:
$ ->
class Item extends Backbone.Model
name: null
class ItemList extends Backbone.Collection
model: Item
class ItemView extends Backbone.View
tagName: 'li'
initialize: =>
#model.bind('change', this.render)
#model.view = this
events:
'click' : 'clicked'
clicked: ->
console.log 'clicked'
render: =>
this
class ItemListView extends Backbone.View
el: $('ul#test')
initialize: =>
$('li', #el).each(#addItem)
addItem: (item) ->
item = new ItemView({ el: item })
render: =>
this
Items = new ItemListView
HTML:
<ul id="test">
<li>Hi thar</li>
<li>Yeah</li>
<li>OK</li>
</ul>
Here's a jsfiddle I started earlier: http://jsfiddle.net/Saxx4/
I never really like CoffeeScript (Javascript is so nice, why replace it?), but it looks like there are a few issues here:
You're getting an error on #model because you never set it on the ItemView. This doesn't happen automatically - you have to either instantiate the view's model in initialize() or pass it into the constructor, e.g.:
addItem: (item) ->
model = new ItemView({
el: item,
model: new Item({
// assuming you might want the list item text
// in the model data
text: $(item).text()
})
})
You usually just want to specify a selector in el, not a jQuery object - otherwise the DOM might not be ready when you load your Backbone code: el: '#test'
You need to pass an options object to the ItemListView constructor, not just a single argument, no matter what you do in initialize():
class ItemListView extends Backbone.View
initialize: (opts) =>
opts.items.each(#addItem)
// ...
Items = new ItemListView({ items: $('ul#test li') })

why do bindAll in backbone.js views?

In backbone's todo demo the code has a few spots where _.bindAll(this,...) is used. Specifically it's used in the initialize function of both views. As far as I can tell it's necessary to do the following:
this.$('.todo-content').text(content);
But why would one want to do the above, when one can do:
$('.todo-content').text(content);
?
_.bindAll( this, ... ) is necessary not only for this.$( selector ).doSomething() but generally to be sure that this in your view's method is always pointing to the view itself.
For example, if we want to refresh our view when the model changes, we bind the view's render method to the model's change event:
initialize: function() {
this.model.bind( 'change', this.render );
},
Without _.bindAll( this, 'render' ), when the model changes this in render will be pointing to the model, not to the view, so we won't have neither this.el nor this.$ or any other view's properties available.
As of Backbone 0.5.2, it's no longer necessary to use _.bindAll(this...) in your views to set the context of the "bind" callback functions, as you can now pass a 3rd argument to bind() that will set the context (i.e. "this") of the callback.
For example:
var MyView = Backbone.View.extend({
initialize: function(){
this.model.bind('change', this.render, this);
},
render: function(){
// "this" is correctly set to the instance of MyView
}
});
this.$ limits jQuery's context to the view's element, so operations are quicker.
Additionaly, this.$('.todo-item') won't find your elements with todo-item class outside your view's element.

Resources