Display selected model from sidebar in information bar - backbone.js

I'm working on a application which has sidebar on the right side. That displays collection. Each model of the collection has select behavior.
In the top center of the page I have one independant backbone view which acts like "info bar" and this view should update it's infomation when I select one of the views in the sidebar
How can I do it? I think that the each view in the sidebar should have "selected" event with model argument, and my question is how can I listen that change in my info bar view in Backbone.js???

This sounds like something that would be served well by an event aggregator pattern. Derick Bailey posted a really nice article on this matter which you can read here.
Event Aggregator Pattern
I extended my Backbone.View so that all views have the event aggregator object available to them like this.
Backbone.View.prototype.eventAggregator = _.extend({}, Backbone.Events);
Basically when your model view is selected, your view.eventAggregator will trigger some custom event.
sidebarView.eventAggregator.trigger('selected', this.model);
or something of this sort. With Backbone events, you can pass parameters through the trigger function to your event listener. In the above example I passed the model with the specific event.
In your main view, you'd be listening for this event.
mainView.eventAggregator.on('selected', myFunction, this);
myFunction: function(model) {
// Some code to execute - model is available through param
}
It's a pretty useful pattern. Just don't forget to unbind the event when you close out your mainView. :-)

Related

backbone events binding to buttons with in and out of template

In below example it has two buttons "Add" and "ClearAll".
`http://jsfiddle.net/naveencgr/L3orucjm/3/`
"Add" button is inside the template which is loaded by backbone on view render and Clear All button is loaded normally as in html.
I had events for both the buttons in view, but click event on normally loaded button is not working . Why?
i have seen this question asked in backbone github forum. I thibk it is designed this way. each backbone view events only involved with items inside the view.
in order to use the outside event you either put thie inner view into theoutter view or simple use jquery event for it. basically backbone authors believe this is more elegant and secure and this will not be changed at least for now.

Change details on Backbone.JS collection change event

Is there a way to gather more information about the changes from within the Backbone.JS collection change event. What I would like to figure out is whether or not it possible to to know what the collection change was; was a model updated, was one added or removed from the collection and also, for every of these, figure out which one.
Different events
When model is added to collection
collection.on('add',this.someFunc,this);
When a model is removed from a collection.
collection.on('remove',this.someFunc,this);
There is no change event on collection but you need to listen on models change event for change
in model:
initialize:function(){
this.on('change',function(){
this.collection.trigger('change');
});
}
Now on collection you can hear for change event
collection.on('change',this.someFunc,this);
refer this for list of all backbone built-in events

Handling in View vs Handling in Controller Extjs

When we working on a extjs MVC project, we can handle a view event either inside the view or controller. How do we decide what events been handled in the view and what events been handled in the controller. What is the best practice.
For example, I need to pop up a window when a button is clicked. Should the creation of the window goes to controller or resides in the container view object.
One thing you can do is utilize the control() method within your controller definition. For example, take this code,
Ext.define('AM.controller.Users', {
extend: 'Ext.app.Controller',
init: function() {
this.control({
'viewport > panel': {
render: this.onPanelRendered
},
'#editform button[action=save]': {
click: this.onClick
}
});
}
});
This is from the MVC example. You'll notice that it is using the ComponentQuery Language (http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.ComponentQuery) to select a set of Ext objects to assign the render() event. This is saying, for all panels in the viewport, call onPanelRendered() for the render() event. So in your case, you want to select some buttons. So I added another example that selects some form with an id of editform and then select the button that contains the property action = save. You can get very specific with these component queries. I would suggest reading ComponentQuery portion of the API to see further examples. This depends on how you are attempting to select the buttons.
If you are new to MVC maybe you should only listen to events in the controller, once you have developed a couple of projects and you've gained discipline and enjoyed the benefits of listening events in a controller then you would be able to mix it up (when to use a handler and when to use a controller is gonna become obvious).
E.g If you have a FormPanel and you are only gonna listen to a button's click perhaps it doesn't make much sense to create a controller just for that, but in the other hand if you have a grid with a toolbar, action buttons, itemClick's etc then it would be a good idea to have a controller for that view.
The fact that you are using MVC does not mean you are not allowed to use handlers anymore, but do it wisely.
Best regards.

How can I trigger two events with a "double" action?

I've got a view Foo, with an input field, and a wrapper view Bar, with a button.
When I write something in the input and then press the button, the 'change' event on Foo's model should be triggered, and then the 'click' button on Bar's, yet only the first do happen. Is there a way to trigger both, preferably at the correct order?
Thanks!
To reiterate, and confirm your question/setup. Based on your question, this is the setup you have. You want to change the Foo.model THEN trigger the click event on the Bar.
<div id="Bar">
<div id="Foo">
<input type="text">
</div>
<button id="barButton">Update</button>
</div>
It's a little bit of an odd setup. #alexanderb illustrates it the way I also think of the whole problem but I'll explain what I'd do in your scenario assuming you know something I don't about the context of the situation! :-)
If you want the change to be triggered on the Foo.model followed by the click event on the Bar button, all you need to do manually trigger the button click from your Foo view. To do this, you can do it one of several ways. The first is to directly trigger the event of your parent (Bar) view.
// When you create your Foo subview, you pass in the parent view so you can access it
var foo = new Foo({
'parent': this // this = the barView assuming you're creating FooView inside BarView
});
// In Foo after you set your model attribute, you access the parentView
this.options.parent.$el.find('#barButton').click(); // Manually trigger the click event
// or
this.options.parent.onButtonClick() // Manually run the event handler bypassing the event
This satisfies your request to have the change event followed by the button click event in the DOM context you provided. (Not sure why in this case but I can imagine some scenarios where something similar might be desired.)
The second way of doing it is to use an event aggregator pattern which allows your views to send and receive events to one another. In this scenario, what happens is your Foo view, after updating the model triggers an event that is listened to by your parent Bar view, upon which it executes some handler.
You can read more about event aggregator pattern in Backbone here:
Event Aggregator Explanation
To be honest, I really think that alexanderb's answer is the best one for this situation unless there is something more we don't know about your special setup. But, I hope you can see and compare the two and get an idea of when and why one setup might be appropriate given a particular context.
Hm, I'm a little confused. If you don't use any backbone plugis, the workflow is different.
If you press something on a screen, an event occures on view, not in model. You have to listen to that event and update the model accordingly. If you set new value in model, change model event will occur.
Say, you have a view Foo it's subview Bar and model Boo. Both views are using the same model objects.
In Bar view,
events: {
'click .button': 'onButtonClicked';
}
onButtonClicked: function () {
var value = this.$el('.input').val();
this.model.set({ someValue: value});
}
In Foo view, you can listen for model changes
initialize: function () {
this.model.on('change:someValue', this.onSomeValueChanged);
}
In this.onSomeValueChanged you can do, what ever you like.

Adding to a collection from a popup modal with Backbone Marionette

I'm pretty new to Backbone and Marionette and am having a tough time getting my views to communicate.
I've got a composite view that displays a list of items. To add a new item to the list, I have a popup modal that opens in a new item view that is separate from the composite view.
I'm not sure that this is the best way to do this, but in the modal, I created a new instance of the collection with all of the items and added the new item to that collection. This new item shows up in the original composite view, but only after I refresh the page.
I can't seem to figure out how to get the composite view to listen for the add event and render the new model after it is added.
Am I on the right track here? If not, what should I be doing to add to a collection from a modal?
I think I got this figured out. Instead of creating a new collection in the modal view, I passed in the collection from the composite view as a parameter when I created the modal view. Now, when I add a new model in the modal, the 'add' event is automatically triggered on both versions of the collection and the view automatically renders the new model. No need to bind any extra events like I was thinking.
Your solution will work, but means your views are pretty tightly coupled. You might want to look into using events instead (see How do I send a model that was clicked on within a ItemView to another ItemView that is on the same page?)
How your functionality would work with events:
Within the modal, you enter the data for the model to create
When you press the "save" button,
you validate and save the model var myNewModel = ...
you trigger an event: MyApp.MySubApp.trigger("item:add", myNewModel)
In the controllerfor the list view, you listen to that event, and add the new model to the collection.
The handler code in your controller would look something like:
MyApp.MySubApp.on("item:add", function(model){
this.myCollection.add(model);
});
If you'd like to learn more about using events, check out 2 Marionette tutorials I wrote:
http://davidsulc.com/blog/2012/04/15/a-simple-backbone-marionette-tutorial/
http://davidsulc.com/blog/2012/05/06/tutorial-a-full-backbone-marionette-application-part-1/
Both use events to communicate information within the apps.
In addition, basic events are also explained here: http://samples.leanpub.com/marionette-gentle-introduction-sample.pdf

Resources