How to connect multiple MVC elements/modules for the same page? - javascript

I have multiple UI elements on the same page. Each of these elements I divided into Model/View/Controller. They act as modules and most of the functionality is independent to the rest of the page. Controllers deals with user interactions for that specific UI element. Model contains the data and Notifier to update the View if any data changes. Some user actions might require to collect the data from another Model and then I need to trigger another Models View. How can I connect those MVC elements with another MVC elements in the single page?
At the moment, I thought of couple solutions.
Create a big model, instead of having small models and pass it around as a dependency to each Controller. Then notify that specific view.
Create some kind of model to model relationship between two elements, so that state change on one model would affect the other model (Through dependencies, notifications).
Create Controller to Controller relationship between two elements. Maybe something like explained here: https://www.youtube.com/watch?v=w7a79cx3UaY&t=678
I would like to avoid big models and somehow retain independent modules. I am not sure how you can connect multiple MVCs in that matter.

Related

Backbone.js views and models correlation?

Background: I'm using Backbone for the first time. In my project, I have one "main" model - let's call it Customer. At all times, only one Customer is displayed. I have a CustomerList Collection, which queues the Customers. At a button click, the next Customer is displayed. CustomerView does all the rendering etc.
The problem: should I make a new instance of CustomerView every time we switch to the next Customer? Another possibility (which I started out with) was just one instance of the View and passing the model to the render function of the view (view.render(model)). This way, I can get the next Customer from the List, pass it on to the render function of the view and that's it. I'm wondering though how well this suits the MVC pattern of Backbone? It would seem more "standard" to get the new model, kill the current View and make a new View instance.
Any suggestions from experienced Backbone developers, please? Thanks.
If the only thing that is changing is the actual model then you should definitely keep your CustomerView around and simply provide it a new model to display.
This most certainly pertains to MVC concepts of functional separation. The CustomerView only needs the relevant data (supplied by the model) in order to perform it's task of rendering the view.
Think of it like this - is there any need to reset your CustomerView module? It shouldn't hold and model specific information at all so essentially it shouldn't care that you change the model - only that it needs to be re-rendered once the data changes.
The one instance where it would make sense to me to totally "kill" the current view would be if the user navigates to a different section of your application that has no relation to customers and has no option to view customer details. Only then would it make sense to completely release un-needed modules.

How to structure the use of many views in a backbone router

I'm making a single page application using Require.js and Backbone.js. Its a fairly large web app with a lot of different "pages" aka views. Below is my router to give you an idea. There are several main pages with sub pages.
So for example there's a Settings section that has multiple different sub pages such as user settings, language settings, email settings etc.
How would I structure many routes and their views for simplicity?
Right now Im giving each sub page its own view but that means I have to import 20-30 views into the router so that all possible views are available for when that page is routed.
Another way I thought of was to have one view for each section and that in that view I should load different partials. That way I only have to load the 5-6 section views into the router... but then the view would have to understand routing.
Whats the right way to do this?
I create 'controller' objects that take care of view rendering and model fetches.
I prefer to keep the router clean at all times, which means that I will don't clutter it with callback functionality. Doing so would make the router a mess over time, while part of its purpose would be to get a quick overview of the available routes.
In Backbone, I found that it is useful to create your own conventions, just like a framework would do.
For example, for every view I create, I will create one controller object.
Every controller object has a method that is named 'makeView()', and which takes care of rendering the view, as well as memory management.
In my own theory, I created a method of 'cascading controllers', in the sense that one controller may also control other controllers, and controllers may use 'helper' objects to fulfil certain tasks.
For example, when you say that you may need to manage 20 views and subviews; we could imagine that some of the views are related to each other; that there will be a central controller that takes care of common tasks between related views, and specific controllers that take care of specific, individual view functionality.
A route in my router looks something like this:
auth: function(){
//--- Check the authStatus and render status independent views
var auth_ctr = new Auth_ctr();
auth_ctr.makeViews();
}
In the example given, you could imagine that you will create and render multiple views. So what I really do, is instantiate new controllers from within this controllers, that each individually will create and manage views, provide functionality that support the view, get the collection/model data.
It would be important to create a sort of independent 'View manager' that prevents memory leaks from occurring when you render new views each time.
This is just how I do it, but of course, I'm sure there are people who do this differently.
It is a theory I came up with; it has given me a clear structure, and it has worked well for me until now.

call two web services from one store in sencha touch

I want to call two web services from one store and want to bind them with a listview in sencha touch.
For example, I have two web services which are as follows:
1. Company
comp_id
comp_name
emp_id
2. Employee
emp_id
emp_name
Both of the services have different urls and I have to use these services separately as I don't have control over a customer's database.
So now I want to create one or two models & one store for these two webservices, so that I can simply bind it with the lisview and show it in sencha touch.
But the issue is that store has a proxy which can fire only one request at a time. How can I aggregate it in a model and display it in a list view ?
Disclaimer: You shouldn't do it this way. It just doesn't make sense. Models, stores, and dataviews are meant to operate a certain way. By breaking this concept too often you will only be kicking yourself later on when things get more complex.
With that said, I still understand the reasoning and here are some ideas I recommend:
-Normalize the model and dataview templates (use only one model with generic field names). Don't use the store proxies to call the API, instead just do independent Ajax/JsonP requests asynchronously, map the results to the normalized model fields, and add model records to the store. This allows you to add the data from one or more sources as needed, independent of each other.
-Add logic to the proxy on beforerequest. When loading the store, pass custom arguments and handle them in this logic to switch URLs. Then handle results on requestcomplete to set them to the relevant models. You still are faced with the issue though that really one model = one store.
-Consider doing something like the above, except use store associations. One model can be the associated model and you can use the provided relations functions for templating.

Backbone - shared model

I started reading some Backbone tutorials and I found one thing that astonishes me. Why models are created inside of view? What if I want two different views for one model (what I think MVC is for)? Let's say I need a model Colors, DisplayView view which displays them and ControlsView which allows me to set their configuration. How to handle this?
Backbone does not require that you create your models inside your views - you can (and often should) create your models independently of your views so that they can be shared. Also, just because you create a model inside a view doesn't mean you can't pass a reference to that model to another view and share it that way.
Most likely the tutorials you are reading are very simple and create single models for single views to make the tutorial easier to follow.

Backbone: Are Views really Controllers?

I'm building my first Backbone.js app and I'm confused about how much responsibility I'm supposed to give to or hide from my Views.
In my example, I'm building a Rich UI Table (similar to YUI's datagrid) that's dynamically generated from a Collection. In my app I call this an "AppTable". In my understanding of MVC, I would imagine that there'd be some kind of AppTable controller which finds the correct Collection, grabs a "dumb" View and passes to the View whatever information from the Collection it needs to render. In this senario, the View would do little more than take the data provided to it and modify the DOM accordingly, maybe even populating a template or attaching event listeners.
Backbone seems to do away with the idea of having a controller mediate between the View and Collection. Instead a View gets initialized with a reference to a Collection and it is View's responsibility to update itself.
Am I understanding this architecture correctly?
Assuming I do, my question then becomes, what happens when my View needs to do more and more? For example, I want column sorting, drag-and-drop for rows, pagination, searching, table control links (like new, copy, delete row... etc), and more. If we stick with a "smart" View paradigm where the View is connected directly to a Collection, do the above functions become attached to View object?
Thinking through this, I could see the View growing from a simple table wrapper to pretty messy beast with lot of functionality attached to it. So, is the View really a controller in this case?
Your understanding of the architecture is correct. Backbone does not recognize the concept of a "controller" in the traditional MVC sense. (In fact, Backbone used to actually have an object called a Controller, but it has been renamed Router to more accurately describe what it does.)
The functions you list (drag-drop, delete rows, sorting, etc.) would all belong in a View. A view describes what you see and responds to user input. Anything involving an event (a click, a keypress, a submit, etc.) all go inside of a view. But your view should never actually manipulate the data; that should be done by its model. You are correct in thinking that a view acts like a controller, because it packages data and sends it to the model, which will then validate/set/save appropriately. Once those actions have occurred, the view re-renders itself to represent the new version of the data inside the model.
One note of caution: your view should not be too strenuously tied to the DOM. It is Backbone convention to have a top-level DOM element that your view is tied to (e.g., a form or a div) and then deal only with its sub-elements. That is appropriate; in general, things like "remove this link from this div" inside your view are not. If you find your view growing unwieldy, you most likely need to break it into subviews, each with their respective behaviors as components of their whole.
My thoughts on this updated below:
I think Josh gave a good answer, however, in my experience, building a few Backbone apps, even medium-complexity apps do need a separate controller class.
To clarify what I mean about a controller: The functionality between the model (or router) and the view that creates and instantiates the new view class and kills (and unregisters events) on the old one. This functionality might be the same for many views (so a direct one-to-one relationship between views and controllers probably isn't needed) but sometimes one needs to pass in a model or other additional extra values.
Right now, I just have one controller with a few if statements for adding some unique data to certain views for most apps I've built but I'm looking at setting up an architecture where it will check to see if a unique controller exists for that view else it falls back to the standard controller. Nothing special, but should do the job.
Update: After six months of building Backbone apps I realized that routers can be split up and extended just like views. (duh?)
Right off the bat, I knew to make a base view of functionality I know that all my views would need. Similarly, I would make base views for each section, like "profile" pages or "inbox" pages that I know would all use the same functionality. This wasn't so clear to me in the beginning with routers, but the previous name of "Controller" hinted at this.
Most people (as in every example of Backbone I've ever seen on the web) just use one monolithic router instantiation to handle all routes but you can actually have 1-to-1 parity of routers to views, or in my case, a base router for checking user auth and such and then one for each major section. That way if you need to pass in certain models or collections to a router on page load, you don't need to add code to one monolithic router, but instead pull up the unique router for that view. I find this is currently better than creating a separate controller class. The base router can be in charge of last instantiated view, etc, so you can kill the last view before instantiating the new one.
TLDR: Use multiple Routers as controllers. I believe that's what they were meant for and it works well.
I've struggled with the same semantic issues when trying to map out a single-page app. In the end I decided that Backbone is using the wrong name.
When you look at a Backbone app in the browser, the View is not actually a view at all, its el member is the view. Backbone.View is either a view controller or, probably more correctly, a presenter.
Some supporting evidence:
you never see a Backbone.View on the screen, its always the el or $el that is applied to the DOM
a Backbone.View does not receive user input, the DOM element receives input and the events are delegated via the events hash of the "view"
a BackBone.View manages model or collection changes and translates these changes to dumb-view (DOM) elements, then applies them to the actual view, e.g. this.$el.append('<p>Cats!')
I think Backbone.Presenter would be a better name, but I can also see the historical issues with there being a former Backbone.Controller and the amount of work renaming introduces.
I have settled on the following structure for my latest project:
an app controller, extended from Backbone.View, tied to the body element
several model collections to cache data retrieved from the server
a Backbone.Router that translates route changes into Backbone events and triggers them on itself
many app controller methods that handle the router events the app controller listens to
an app controller method prepares any needed models, then initiates a presenter (extended from Backbone.View) and attaches it to the body element
All these parts are initiated and owned by the app controller. The presenters do not know why or where they are on the page and only care for their own DOM elements and the changes they receive from this.model.
Have a look at this part of backbone documentation
http://documentcloud.github.com/backbone/#FAQ-tim-toady
References between Models and Views can be handled several ways. Some
people like to have direct pointers, where views correspond 1:1 with
models (model.view and view.model). Others prefer to have intermediate
"controller" objects that orchestrate the creation and organization of
views into a hierarchy. Others still prefer the evented approach, and
always fire events instead of calling methods directly. All of these
styles work well.
So, backbone does not take that decision for you.
I have a very similar use case (table grid with pagination, ordering, live filtering, and forms with client-side validation, master-details relations, etc.)
In my case, I first started with a Router behaving just like a controller, and quite quickly my code got a bit messy.
So I completely removed Routers (I'll add them back later, but just as an addition) and created my own controller (that in fact works as a presenter). It's just a javascript class, with Backbone.extend backed in to handle inheritance.
The idea is that the view recieves all the data it needs to display itself (model, collection, and the el in which it should be parsed), set up listener on dom events, and then executes controller methods. It never directly modifies the data nor it interacts with other views, it tells the controller to do it.
A view can have subviews, and in that case the subview only interacts with the parent view, or directly with the controller.
So far now it seems to work, but anyway things are not so simple as I expected them to be...
I hope to publish it in the next few days.
A different perspective from the other answers here is that, just because you are using the Backbone framework, that doesn't mean that your entire codebase must be wrapped in Backbone classes.
Personally, my controller is an amalgamation of "raw" Javascript and Backbone routes, and I never use Views for control logic at all. IMHO views are for ... well, view logic, and specifically for wrapping elements. If you're using a view for anything that doesn't directly connect to an HTML element you are (again, IMHO) doing something wrong.
Backbone is awesome, but that doesn't mean that it's a silver bullet that can be applied to everything.

Categories

Resources