Backbone Design - Multiple Views, Same Model, separation of events - javascript

I am quite experienced with JS and Backbone, but want your help brainstorming a best practise solution to the following problem:
There are two views. They sit side-by-side running concurrently in the page.
Both of these views are passed the same instance of a model.
Both of these views have actions which can update the model.
How, using Backbone's event driven programming, do you think would be the best way of distinguishing the events fired from view to view.
A possible scenario could be:
The user performs an action which updates the model in an invalid way on View A. But as the user did not perform it on View B they should not be notified there.

You can use intermediary objects to manage the flow between a repository (the object where the connection to the database takes place) and the instantiation / manipulation of views.
Instead of binding a model to a view from within the view, you can let the intermediary object (general purpose controller) make verifications, if required manipulations, before re-rendering the view with the modified model or collection.
Through the use of an event aggregator, you can trigger events from views from within the view, and listen to the event from within the "controller" object, who will in turn perform the required custom actions.

Using custom events seems simple enough. Just treat each view's actions as if they were different and name the events differently for each view (example this.trigger('view1:event1'), this.trigger('view2:event2')).
Make sure the views are subscribed to these specific custom events to avoid collisions on actions that would trigger events on both views (like attribute updates).

Related

How to catch Subview events in the Controller?

BackboneJS app built with RequireJS modules.
A View has multiple instances of subView. Click events in a subView should run Controller methods.
Initialization order requires View module in Controller, so requiring Controller module in subView would create a circular dependency.
I would prefer to create Events to convey data to Controller. Considered two options:
View listens to subView events and fires own Events, listened by
Controller;
Have a third app-global object, subViews trigger
events on that object, Controller listenes on that object?
What is the best pattern here?
Marionette has event bubbling in place. For example if a view triggers "some:event", you can listen it on collection view as "childview:some:event".
If you have really deep views structure, then "childview:...childview:some:event" starts to look really bad and then you might consider three options: manually bubble them, use global message bus like "backbone.radio" or passing down some entity to fire events on it.
I personally feel bad about global bus and prefer to have for each meaningful part of application something that would implement mediator/observer pattern. Basic implementation might be state model, created in controller (or router) and passed in all the views below - then any of them can change something in state or listen to changes.
Actually as Controllers were deprecated in Marionette 3, it might be a good idea to move all the controllers logic inside these state models. Unfortunately as Backbone community is on decline I can't find any good resources on the topic.
If is only one case, option 1 is right.
But if is a common operation, with multiple events and needy by many views: the 2 option may be better.

Are event handlers in the view or the controller in an MVC application?

I am currently enrolled in a course on JavaScript Design patterns and I wanted to clarify the proper place for event handlers.
I noticed my professor's code included click handlers for a client side application in the view section -- my code accomplishes the same outcome, but I included click handlers in the controller.
In an MVC application, should event handlers be in the View or the Controller?
I think MVC in the web can only really loosely be considered true MVC. In the case of ASP.Net MVC, your javascript events can only really be part of the view (although should be separated into js files).
If you want to separate the js events from the view entirely, you're going to have a hard time. You're better off making an educated decision on which events are really related only to the view, and which need to interact with the controller.
For example, clicking on a menu item to expand and display sub-items, is 'an event' but the controller doesn't need to know about it. But loading data based on some selection would need to post, or submit through ajax, data to the controller.
In an MVC application, event-handling should definitely be placed in the view. It's a common misbelief by programmers not really aquainted with software design patterns, that event handling belongs to the controller maybe because of its name (controller = sth. that controls sth. ...).
The reason is that of portability, reuse of code and modularity: imagine you want to run your application on differrent platforms: PC, web, mobile phone device. Each specific platform has its own GUI-frameworks, libraries etc., so if you place event handling stuff, which is 100% GUI-platform specific (e.g. javafx, swing, android, struts, gwt ...) in the view, you can reuse the controller and the model and only have to deal with a new custom view.
The controller can be seen as a mediator between the view and the model, a middleware which is responsible for proper interaction between model and view.
Generally view should not have any logic besides rendering. So if you handler needs to call the server ( or do something else not related to rendering ) than it should be either in a model or a controller ( depending on a framework ). If you handler needs to do some animation, that logic probably should stay in a view ( if animation only pertains to a view ).
Usually when some event is triggered on a view it calls some method on its model ( view model ) that update the state of the model. When model is done updating its state ( synced with a server ) it fires an event that its view listens. When view sees that its model got updated it re renders itself.
Controller ( or may be a router if it functions as a controller ) usually only instantiates views and models.
Actually all of that will probably depend on a framework that you choose. I use backbone.js.

Using backbone with multiple views and little models

I use backbone in most of my projects, and I think I know exactly what the M V C means: M for abstract of the data, V for representation and C for handlers.
However during my current project I found that there are a lot of views interactive with each other, while there are little modes(data with the server).
For example, I have there complex view named V1 V2 V3, when user do something in the V1, V2 should respond accordingly, so does the V3 and etc, and at the last step, a requst may be made to request data from the server. And most of the request are used to fetch data rather than modify data.
It does not like the common style: one(or more) view for one model such as the CRUD operation.
Now I have two ideas:
1 Virtual model
Create a backbone model to represent the state of the whole application, bind this model to all the views. Sounds like make the application as a state machine.
While it is not easy to describe the application with different states.
2 Use the event mediator
Use the event mediator to register/un-register different events, then the views can trigger or respond by different events.
While how to define the events to avoid insufficien or excessive, in a word to make the events orthogonal is not easy. Or I have not found any instructions yet.
Is there any other alternative solutions?
I think that it is a quite relevant question actually.
Create a backbone model to represent the state of the whole
application, bind this model to all the views. Sounds like make the
application as a state machine.
This doesn't seem like a very good idea, if the model isn't a consistent representation that corresponds to a specific backend resource.
Ideally, a view is a representation of a single model or collection. When a view would be bound to a model with unrelated properties, this doesn't seem too practical to manage in all circumstances, also due to an unforseeable future.
Use the event mediator to register/un-register different events, then
the views can trigger or respond by different events.
I don't think that it is overall a good idea to make views respond to custom events but this is personal for me. When apps become larger, assigning too much responsibility to complex views can become a mess; therefore I take it as a general rule to limit the task of the view to:
Rendering templates;
Activating plugins (if they're specific to the view);
DOM event binding;
(Model binding);
Methods internal to the view (related to the DOM);
Triggering custom events to notify other listeners when further action is required after interaction with the view;
In any case, in my experience I've found that it is practical to use a custom presenter/controller to instantiate / update views on custom events, and not let the view itself worry about these things at all. It keeps them clean and you always know what you will find there.
The views 1, 2 and 3 as you mention can be re-rendered from the presenters.
The presenter does something like:
"I get some data from a service and give it to some of my views that require
them. If something changes, I'll let them know"
I usually have 1 presenter per related set of views.
I like this approach because:
It keeps logic for related views centralised;
When an event is triggered, the presenter needs to listen only once for all the views that it controls;
Presenters are given the authority to talk to each other, which is to my feeling easier to control than when all views would start talking to each other through each other;
In simple cases, all of this doesn't matter too much probably. But when building a larger application, I found that it can become a mess.
My two cents
I have there complex view named V1 V2 V3, when user do something in the V1, V2 should respond accordingly, so does the V3 and etc
It doesn't seem like you have 3 views, but in fact 1 view with 3 interrelated sections. I would use one super view that renders 3 child views, and listen to view events. For example:
Backbone.View.extend({
initialize: function () {
this.v1 = ...;
this.v2 = ...;
this.v3 = ...;
this.v1.on('user do something', this.v2.respondAccordingly);
this.v1.on('user do something', this.v3.soDoesEtc);
}
})
And in view 1:
$('button').on('click', function () {
self.trigger('user do something');
})
This is a problem that many Backbone developers face.
What I've done in the past is to have a baseModel/baseCollection, and treat them as an abstract class/interface from which other models/collections extend, respectfully. These base objects would contain a listener/trigger methods which I could then use across my application to have changes in one model/collection be able to initiate updates on collections/models (thus triggering view changes) respectively as I chose. Using this method allowed me to compose my application by having the appropriate objects listen/broadcast events appropriately as I wished.
One of my friends created a server-side JS state machine which would initiate super-models (app-level model which in turn could trigger sub-view model/collection updates).
Of course, Marionette provides a framework that makes this a little less manual and allows you to get back to writing app-code.
One of the joys and burdens of Backbone.js is that you have all the flexibility you want. :)

backbone design queries

In an MVC controller is what holds the business logic. In backbone the
controllers have been renamed to route. Now there are couple of things
which bring in confusion.
Model should have business logic.
Collection is the collection of models.
Views are where the templates are rendered, and most of the DOM
event handling is done.
Apart from routing, what do the routers do? And where should more
of business logic go to the routers or to the models?
Do the views perform anything extra other than rendering DOM
variables?
Yes they should, also should be the ones with a "link" to the Backend, to do the CRUD, but can also validate object state, ensure backend and frontend model sync and other things.
Correct again, but they also have a very nice use that is to fetch lists of models from the server very easily.
They should also attach event handlers to HTML elements and models and react to those events accordingly.
4.They handle all URL changing events and direct them to display the proper views for that URL, routers give you the opportunity to change your page completely and keep track of the URL changes by using Backbone.history, so Back and Forward Browser buttons will keep working.
They do the URL mapping.
It's an awesome framework, I can't live without it anymore.
IMHO:
You don't need to use routers et all, if you use them the should just route.
Views should contain all the DOM/Model-Event listeners.
Some Ideas on structuring: http://ricostacruz.com/backbone-patterns/

Any pointers on cleaner way to maintain state accross view in backbone.js application

I have two dropdowns in a view along with some links. If I change values in a dropdown, data gets refreshed in the view. I need to maintain the changed state of the dropdowns to the next view.
Any recommended way of doing this?
Is maintaining state really the way applications are written in backbone?
As is being advised in the comments, backbone.js would have you manage your data in models outside of the view. You still have data in the DOM, but you serialize it into data managed by a model.
In your particular case, it sounds like you may have one underlying model which is used by two views. Your first view probably needs to register a function for a DOM event triggered when the drop down changes. This function then updates the underlying model. If you other view is on the page and if it has registered to listen for the model's 'change' events then it can refresh itself. Whether it does or not, the underlying model should have the same data.
I think the best advice to give you is to re-read the backbone.js documentation and carefully go through any examples that they give or that you can find otherwise.

Categories