(Let me preface with I am new to Backbone and Backgrid.) I am using Backgrid and select-all extension and I was having issues "catching" the event that the select all fires in my containing/parent view. I want to show a details view when a row is selected in the master grid. So, I need the select event in the grid to bubble up to the parent view so it can show the details in another view.
var view = Backbone.View.extend({
el: '.grid',
initialize: function () {
var columns = [{
name: "id",
label: "ID",
editable: false,
cell: "string"
}, {
name: "",
label: "Action",
cell: "select-row"
}];
var grid = new Backgrid.Grid({
columns: columns,
collection: this.collection
});
$("#backgrid").append(grid.render().$el);
});
});
Now I am thinking I want to add something like this to the view
events: {
"backgrid:select": "<name of the function i want to call>"
}
But that doesn't seem to work. Any help would be appreciated.
I was able to answer my own question...in the view add....
this.collection.on('backgrid:selected', function(model, selected) {
//do what i need here
});
backgrid is already triggering the event backgrid:select (which is handled via the model) but it also triggers the event backgrid:selected which bubbles up in the collection...which in turn is accessible via the parent view.
A reference to the official API documentation pointing this out can be found here
Related
I have two views each bound with their own collections. i have a save button on the screen on third view.
How can i save both the collections in single save click?
You didn't provide any code to help us answering you, but I'll try to help. Here is some code that you could implement:
var View3 = Backbone.View.extend({
events: {
'click .saveButton' : 'saveCollections'
},
initialize: function(view1, view2) {
this.view1 = options.view1;
this.view2 = options.view2;
},
saveCollections: function() {
this.view1.collection.save();
this.view2.collection.save();
}
});
You'll need to pass as params your previous views (View1 and View2) in the instantiation of your View3.
I want to create a sample page using backbone.js and i am completely new to it.
The view should be similar to the shown in backbone.js website where you have a sidebar and on the right side you have a content.
As shown in this link:-
http://backbonejs.org/
Consider the following scenario:-
var model = Backbone.Model.extend({
data:[
{'title': 'Apple', 'logo':'images/apple.png', 'history': "Some history about apple"},
{'title': 'Google', 'logo':'images/google.png', 'history': "Some history about google"},
{'title': 'Microsoft', 'logo':'images/mirosoft.png', 'history': "Some history about microsoft"}
]
]
});
Now in my view the sidebar should contains links in list form like
Apple
Google
Microsoft
and on the right side, I want to see apple logo and history which passed in the data above.
Similarly when somebody clicks on google on the runtime, I change the content on right side of sidebar
Any guidance on how to get this..?
See the answer below to get the basic idea about passing parameters between views:
Event handling between views
Basically, you have to register an event which when fired, will re-display your main content:
ContentView = Backbone.View.extend({
initialize: function () {
App.vent.on('show', this.show, this);
},
show: function (company) {
// do something with your model, then call render()
}
// ....
});
and a sidebar view which is supposed to trigger that event when you click on any of the links:
SidebarView = Backbone.View.extend({
events: {
'.companylink click': 'clicked'
},
clicked: function (company) {
App.vent.trigger('show', company);
}
// .....
});
i'm building a Backbone/Marionette application to list different sets of cards. the layout has an ItemView on the left side including an input field to add a new set and a CompositeView on the right side to list the card sets.
Cards.module("Set.SideBar", function(SideBar, App) {
SideBar.SideBarView = Backbone.Marionette.ItemView.extend({
template: "#set-sideBar",
className: "well sidebar-nav",
ui: {
saveBtn: "a.saveSet",
setName: "input[type=text]"
},
events: {
"click .saveSet": "saveSet"
},
saveSet: function(ev) {
ev.preventDefault();
var newSetName = this.ui.setName.val().trim();
var newSet = new Cards.Entities.Set({ name: newSetName });
newSet.save();
// How to add the model to the collection?
}
});
});
i'm looking for the best way to add the newSet to the collection of the CompositeView below. is there any clean low coupling solution to deal with that? i'm quite new to backbone.js and can't imagine that this is something totally unordinary, but somehow i'm not able to find an answer to my question in the regarding docs - or just dont understand them.
Cards.module('Set.List', function(List, App) {
List.SetItemView = Backbone.Marionette.ItemView.extend({
tagName: "tr",
template: "#set-list-item"
});
List.SetView = Backbone.Marionette.CompositeView.extend({
tagName: "table",
className: "table table-bordered table-striped table-hover",
template: "#set-list",
itemView: List.SetItemView,
itemViewContainer: "tbody",
modelEvents: {
"change": "modelChanged"
},
initialize: function() {
this.collection.fetch();
}
});
});
thanks in advance for your help!
how i'm doing it now:
thanks for both answers, they were guiding me in the right direction. the collection.create hint was also very useful and solved another problem i was facing!
inside a Marionette.Controller i do something like this and simply share the collection reference:
var setLayout = new Cards.Set.Layout();
Cards.mainRegion.show(setLayout);
var sets = new Cards.Entities.SetCollection();
var listView = new Cards.Set.List.SetView({ collection: sets });
setLayout.listRegion.show(listView);
var sideBarView = new Cards.Set.SideBar.SideBarView({ collection: sets });
setLayout.sideBarRegion.show(sideBarView);
and the new model is simply added by collection.create instead of .save() and .add().
Backbone.Collection.add can be used to add a model to an existing backbone collection.
http://backbonejs.org/#Collection-add
Also, look in to Collection.Create - http://backbonejs.org/#Collection-create
If your model is being persisted, then immediately added to the collection, you can skip your model.save() then collection.add() and just use collection.create(model)
Edit: And as already mentioned, make the collection instance visible from the sidebar view
To keep views decoupled, you can raise events from one view that other view(s) can listen to and handle however they please.
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!
It's an easy example as following:
There are many avatars and only one avatar can be selected each time.
I have a model 'Avatar', collection 'Avatars' and model's view 'AvatarView'.
Also there is a view named 'AvatarAppView' which is responsible to render the app view.
My implementation is as following:
When one avatar is selected, click event is trigged in the model's view 'AvatarView', then it will be selected but cannot make other models unselected.
Are there any nice solutions? Thank you.
Backbone views have Backbone.Events mixed in so views can produce their own events and other views can listen for those events. So your AvatarView can trigger an event when it is selected:
select: function() {
// Mark this avatar as selected...
this.trigger('selected', this);
},
unselect: function() {
// Undo the "mark this avatar as selected" from above.
}
and then the AvatarAppView can listen for those events:
initialize: function() {
_.bindAll(this, 'selected');
//...
},
render: function() {
this.kids = [ ];
this.collection.each(function(m) {
var v = new AvatarView({ model: m });
v.on('selected', this.selected);
this.kids.push(v);
this.$el.append(v.render().el);
}, this);
return this;
}
Then a simple selected event handler for AvatarAppView to unselect the other AvatarViews:
selected: function(v) {
_.chain(this.kids).reject(function(k) { return k == v }).invoke('unselect');
}
Demo: http://jsfiddle.net/ambiguous/thRHK/