How to add a tooltip on all regions and views?
Here is my layout.js:
return Backbone.Marionette.Layout.extend({
template: bearBoxLayoutTemplate,
regions: {
header: ".header",
sidebar: ".sidebar",
workspace: ".workspace"
},
// onShow also didn't work
onRender: function()
{
// tool tips
$('.tooltips').tooltip();
}
});
The code below doesn't work, but if I add the
$('.tooltips').tooltip();
on every view, it works. Is there any other way instead of putting the code on every view?
Thanks!
Got this to work by listening to the show event of the regions on the initialize function of the layout
Here's the code:
// listen to the region on show event
this.sidebar.on("show", function(view){
// manipulate the `view` or do something extra
// with the region via `this`
this.$el.find('.tooltips').tooltip();
});
// listen to the region on show event
this.workspace.on("show", function(view){
// manipulate the `view` or do something extra
// with the region via `this`
this.$el.find('.tooltips').tooltip();
});
Related
I am working on a Backbone application which is based on a dynamic template . I have a header view, a side panel view and footer view that are dynamically initialized when calling any other view .
The problem is I have events on each template view that are not firing. For example i have a button that changes the language in the header view but its event isn't firing.
My header View :
define([ "jquery", "backbone", "text!../../pages/header.html" ], function($,
Backbone, headerTpl) {
var header = Backbone.View.extend({
events : {
"click #enBtn":"swichToEnglish",
"click #frBtn":"swichToFrench"
},
initialize : function(options) {
_.bindAll(this, "swichToFrench","swichToEnglish");
this.render(options.parent);
//$("#enBtn").css("pointer-events","none");
},
render : function(parent) {
this.template = _.template(headerTpl);
$(parent).append(this.template);
return this;
},
swichToFrench:function(){
console.log("switch to frensh");
if(i18n.currentLocal == 'en'){
i18n.currentLocal='fr';
$("#frBtn").css("pointer-events","auto");
this.render(options.parent);
}
},
swichToEnglish:function(){
console.log("switch to English");
if(i18n.currentLocal == 'fr'){
i18n.currentLocal='en';
$("#enBtn").css("pointer-events","auto");
$("#frBtn").css("pointer-events","none");
this.render(options.parent);
}
}
});
return header;
});
The header view is called in the router :
self._header = new Header({parent: $(".main_container")});
Any ideas how to fix this issue. I need to know haw to fire these events Thank You.
The reason your event handlers is not firing is because the event handlers are delegated to the views element, but you're appending the template to some other element. Since the target elements are in this template which is not appended the view's el, the events will never bubble into the handlers delegated to it.
Apart from that, as #mu is too short pointed out, when you do $(parent).append(this.template);,
this.template is the template function. You should actually call it with the data to get the template.
and you shouldn't be using global selectors like $('') and use this.$el.find('') instead as best practice.
also, options is only available inside the initialize method, and is undefined outside.
Instead of passing the parent into the view and then have it append itself to parent, do that outside the view and make the view independent.
Also declare the template property in the view rather than adding it after the creation as a best practice.
And there's no need to bind the context of event handlers to the view manually, by default the context of event handler will be the view.
Your view should look like:
define([ "jquery", "backbone", "text!../../pages/header.html" ], function($,
Backbone, headerTpl) {
var header = Backbone.View.extend({
initialize : function(options) {
this.render();
},
template: _.template(headerTpl),
events : {
"click #enBtn":"swichToEnglish",
"click #frBtn":"swichToFrench"
},
render : function() {
this.$el.append(this.template(/* pass the data here*/));
//--------^----- this is required for the events to work
return this;
},
swichToFrench:function(){
if(i18n.currentLocal == 'en'){
i18n.currentLocal='fr';
this.$el.find("#frBtn").css("pointer-events","auto");
this.render();
}
},
swichToEnglish:function(){
if(i18n.currentLocal == 'fr'){
i18n.currentLocal='en';
this.$el.find("#enBtn").css("pointer-events","auto");
this.$el.find("#frBtn").css("pointer-events","none");
this.render();
}
}
});
return header;
});
Which you can create like:
self._header = new Header();
$(".main_container").append(self._header.el);
it looks like you just want the view content to be added to '.main_container', and doesn't need another element. In that case you can make your views el point to it rather than creating a new element by passing it as el in the options like:
self._header = new Header({
el: '.main_container' // this.el will refer to `.main_container` in view
});
then you don't have to do $(".main_container").append(self._header.el);
if you must pass the parent into view as an options for some reason, then you should cache it in the view inside initialize so that you can refer it elsewhere like.
this.parent = options.parent
side note:
As you can see, I've changed the order in which you had declared the view's properties - initialize on top followed by template, event and render.
We initialize the view, we create the templating function, we declare the events to be delegated, and then we render the view.
The order in which you define properties doesn't matter internally, but when another developer looks at your code, it's much easier to digest. But it's a matter of opinion.
I am working on a Backbone application which is based on a dynamic template . I have a header view, a side panel view and footer view that are dynamically initialized when calling any other view .
The problem is I have events on each template view that are not firing. For example i have a button that changes the language in the header view but its event isn't firing.
My header View :
define([ "jquery", "backbone", "text!../../pages/header.html" ], function($,
Backbone, headerTpl) {
var header = Backbone.View.extend({
events : {
"click #enBtn":"swichToEnglish",
"click #frBtn":"swichToFrench"
},
initialize : function(options) {
_.bindAll(this, "swichToFrench","swichToEnglish");
this.render(options.parent);
//$("#enBtn").css("pointer-events","none");
},
render : function(parent) {
this.template = _.template(headerTpl);
$(parent).append(this.template);
return this;
},
swichToFrench:function(){
console.log("switch to frensh");
if(i18n.currentLocal == 'en'){
i18n.currentLocal='fr';
$("#frBtn").css("pointer-events","auto");
this.render(options.parent);
}
},
swichToEnglish:function(){
console.log("switch to English");
if(i18n.currentLocal == 'fr'){
i18n.currentLocal='en';
$("#enBtn").css("pointer-events","auto");
$("#frBtn").css("pointer-events","none");
this.render(options.parent);
}
}
});
return header;
});
The header view is called in the router :
self._header = new Header({parent: $(".main_container")});
Any ideas how to fix this issue. I need to know haw to fire these events Thank You.
The reason your event handlers is not firing is because the event handlers are delegated to the views element, but you're appending the template to some other element. Since the target elements are in this template which is not appended the view's el, the events will never bubble into the handlers delegated to it.
Apart from that, as #mu is too short pointed out, when you do $(parent).append(this.template);,
this.template is the template function. You should actually call it with the data to get the template.
and you shouldn't be using global selectors like $('') and use this.$el.find('') instead as best practice.
also, options is only available inside the initialize method, and is undefined outside.
Instead of passing the parent into the view and then have it append itself to parent, do that outside the view and make the view independent.
Also declare the template property in the view rather than adding it after the creation as a best practice.
And there's no need to bind the context of event handlers to the view manually, by default the context of event handler will be the view.
Your view should look like:
define([ "jquery", "backbone", "text!../../pages/header.html" ], function($,
Backbone, headerTpl) {
var header = Backbone.View.extend({
initialize : function(options) {
this.render();
},
template: _.template(headerTpl),
events : {
"click #enBtn":"swichToEnglish",
"click #frBtn":"swichToFrench"
},
render : function() {
this.$el.append(this.template(/* pass the data here*/));
//--------^----- this is required for the events to work
return this;
},
swichToFrench:function(){
if(i18n.currentLocal == 'en'){
i18n.currentLocal='fr';
this.$el.find("#frBtn").css("pointer-events","auto");
this.render();
}
},
swichToEnglish:function(){
if(i18n.currentLocal == 'fr'){
i18n.currentLocal='en';
this.$el.find("#enBtn").css("pointer-events","auto");
this.$el.find("#frBtn").css("pointer-events","none");
this.render();
}
}
});
return header;
});
Which you can create like:
self._header = new Header();
$(".main_container").append(self._header.el);
it looks like you just want the view content to be added to '.main_container', and doesn't need another element. In that case you can make your views el point to it rather than creating a new element by passing it as el in the options like:
self._header = new Header({
el: '.main_container' // this.el will refer to `.main_container` in view
});
then you don't have to do $(".main_container").append(self._header.el);
if you must pass the parent into view as an options for some reason, then you should cache it in the view inside initialize so that you can refer it elsewhere like.
this.parent = options.parent
side note:
As you can see, I've changed the order in which you had declared the view's properties - initialize on top followed by template, event and render.
We initialize the view, we create the templating function, we declare the events to be delegated, and then we render the view.
The order in which you define properties doesn't matter internally, but when another developer looks at your code, it's much easier to digest. But it's a matter of opinion.
Here is an example code from the github of backbone layout manager.
The custom render for the view is not getting called/it doesn't stop on the break point.what is happening.
// Create a Content view to be used with the Layout below.
var ContentView = Backbone.Layout.extend({
template: "#content"
});
// Create a new Layout with a sub view for content.
var layout = new Backbone.Layout({
template: "#layout",
// This will place the contents of the Content View into the main
// Layout's <p></p>.
views: {
// Appending a new content view using the array syntax
p: new ContentView({
// Custom render function that reverses everything.
render: function(template, context) {
return template(context).split("").reverse().join("");
}
})
}
});
// Attach the Layout to the main container.
layout.$el.appendTo(".main");
// Render the Layout.
layout.render();
This was answered by the Github when I posted the issue. it should be layout.renderTemplate()
I have a Google Map where user can click (on the map everywhere), the click event opens a Bootstrap modal window, contained a form. My question is, how/where to handle this submit event to add a marker to the marker collection, save it to the db, etc.
Currently I have a Map View, that renders the google map, and adds an event listener for the click. Clicking on the map opens the Modal.
App.Views.Map = Backbone.View.extend({
...
initializeMap : function(){}
...
addMapEventlistener : function() {
google.maps.event.addListener(this.map, 'dblclick', function(event) {
var coords = event.latLng.toUrlValue();
var carray = coords.split(",");
var model = new Backbone.Model({ coords: carray });
var view = new App.Views.Modal({ model: model });
var $modalEl = $("#modal");
$modalEl.html(view.render().el);
$modalEl.modal();
});
}
App.Views.App = Backbone.View.extend({
initialize: function() {
var addMarkerView = new App.Views.AddMarker({ collection: App.markers });
}
});
// add marker view
App.Views.AddMarker = Backbone.View.extend({
el: '#addForm',
initialize: function() {
$('<input>', {
type: 'submit',
value: 'Submit',
class: 'smt'
}).appendTo(this.$el);
console.log('AddMarker init run'); // this echoed out
},
events: {
'submit' : 'addMarker'
},
addMarker: function(e) {
e.preventDefault();
alert('hello');
},
});
my guess is that the form rendered after the click event on the map, so I have to set backbone event listening somehow after the modal opens, and handle the form submission in a collection view, right?
You may want to use the events object to bind your listeners.
About when (re)binding your events. When the view is instantiated, the listeners specified in the events object will be bound to the view element. This implies that if your event targets a child element, the fact that the child exists or not at that moment doesn't matter. Now, you'll have to rebind your listeners in the special case where you change your view element without the setElement method.
Example:
<div id="#mydiv"></div>
And you want to bind an event on the buttons inside this div (you'll create some afterwards.).
Well, here's an example.
Ok, solved. My bad. I added events to the wrong view, I have to add it to the App.Views.Modal view (of course the event happens in the modal). Thanks for the time!
I am trying to add a simple event to the children under my compositeview but it is not triggering at all..and frankly I am not sure why, it seems so simple, I could do this just fine with normal backbone.view.
In the example below, the alert is not triggered at all, however when I purposefully change the function name the event binds to , to something else that doesnt exist, it complaints that the function doesnt exist, so I think it's something else...help?
App.View.ContentContainer = Backbone.Marionette.CollectionView.extend({
className:'content_container',
itemView:App.View.ContentBrowseItem,
events:{
'click .browse_item':'focus_content'
},
initialize:function () {
//this.views = {} //indexed by id
//this.create_modal_container()
var coll = this.collection
coll.calculate_size()
coll.sort_by('title', -1)
},
focus_content:function (e) {
alert('here???')
var $modal_container = this.$modal_container
var content_id = $(e.currentTarget).data('content-id')
var $selected_view = this.views[content_id]
var $focused_content = new App.View.FocusedItem({model:$selected_view.model})
$modal_container.empty().show().append($focused_content.el).reveal().bind('reveal:close', function () {
$focused_content.close()
})
return false
},
onShow:function(){
this.$el.addClass('content_container').isotope({
selector:'.content_item',
resizable:true,
layoutMode:'masonry',
masonry:{ columnWidth:64 }
})
}
EDIT: this is the resulting HTML: http://pastebin.com/uW2X8iPp the div.content_container is the resulting el of App.View.ContentContainer
Is .browse_item a selector for the App.View.ContentBrowseItem itemView element? In that case, you need to bind the event in the ItemView definition, not in the CollectionView definition. The reason is that events are bound when a view is rendered. The CollectionView itself is rendered before any of its child itemViews.
Also, if you are opening up another modal view on this click event, I would let the app handle that, rather than your CollectionView
Try something like this:
App.View.ContentBrowseItem = Backbone.Marionette.ItemView.extend({
...
initialize: function() {
// Maintain context on event handlers
_.bindAll(this, "selectItem")
},
events: {
"click" : "selectItem"
}
selectItem: function() {
App.vent.trigger("item:select", this.model);
}
...
});
And to actually show the modal detail view:
App.vent.on("item:select", function(itemModel) {
var detailView = new App.View.FocusedItem({ model: itemModel });
// You may also want to create a region for your modal container.
// It might simplify some of your `$modal_container.empty().show().append(..).etc().etc()
App.modalRegion.show(detailView);
});
Allowing each of your views to handle their own events is part of what makes Backbone and Marionette so beautiful. You'll just want to avoid one view getting all up in another view's business (eg. a CollectionView trying to handle its ItemView's events, an ItemView creating event bindings to show and close a separate modal view, etc.)
Hope this helps!