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. :)
Related
I'm reading on design patterns and while authors agree that observer pattern is cool, when it comes to design, everybody talks MVC.
I'm a bit confused, MVC diagram is not circular, isn't it natural for code flow to have closed topology ? Why nobody talking this pattern:
model -> observer -> view -> listener -> model -> ..
If view needs controller, then model needs observer, no ? With Object.observe() coming with next JavaScript version, what is wrong with such a pattern ?
The View and and the Controller are both, also, observers.
The view /is/ an observer, of events on the model. The controller /is/ an observer of events in the view. The controller fires commands at the model, which results in it changing which propagates events which are observed by the view which changes its state appropriately.
The problem this is trying to solve is having a UI respond to changes in a model, and having the model respond to input from a user via a UI. There is no great reason to have a third component involved in this, other than the frailty of human vision -- it is far easier to envision a command and control system than an event driven system, though surprisingly the latter is often easier to implement.
One problem with your proposed design is separation of concerns. With MVC (when done properly, with messages/events) each component only knows about itself and its own concerns. With the model you're proposing the Observer component must know how to orchestrate the view, something which the view is better placed to do itself.
Of course, you're thinking that the controller orchestrates changes to the model, so why wouldn't we have an equivalent component on the far side of the relationship?
In fact, although we do typically implement something in the 'controller' space, it's often just 'infrastructure' to pass messages/events/commands from the view to the model, which responds accordingly -- that is, often the controller devolves into a simple router. The need for an orchestration component has been reduced in modern designs due to our better understanding of DDD and the aggregate-root pattern, and of course the possibilities of event-sourcing.
Finally, the pattern you're referring to was originally documented by the Gang of Four as existing in practice and relatively common. At the time there were no mobile or webapps, and one of the largest systems they considered was gimp. As our technologies have matured and our apps are delivered via multiple channels so have the patterns of development in this space. A few years back we were discussing MVC2, then we moved on to oddities like MVVC and MMVC. Now, with CQRS, event-sourcing, and DDD, we have started talking about MV as the orchestration approach has started showing its limitations and event driven systems come to the fore.
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).
I'm trying to implement a MVVM based Single Page Application and currently am using the framework Knockout.js to handle the viewmodel/view portion of MVVM. I'm confused though, as every example I've looked at for implementing Knockout involves saving an entire viewmodel to the database. Aren't these examples missing a "model" step, where the viewmodel syncs with the data-layer model and the model does validation / Server synchronization.
I would like to have multiple different templates/views on the single page each with a different viewmodel. Another thing that I find is missing with knockout.js is synchronizing a single model (not viewmodel) across different views. I don't think it makes sense to have one giant viewmodel that every view shares, so I was thinking that each view would have its own viewmodel but each viewmodel would sync with the fields of just a few application-wide models that are needed for each view.
The page I'm working on fetches a giant model (30+ fields, multiple layers of parent/child relationships) and I think it makes sense to just have all of my viewmodels sync with this model. I have investigated Knockback.js (which combines knockout.js and backbone.js) however I ended up re-writing the majority of the functions such as fetch, set, save, because the page is getting data from an API (and I can't just sync an entire model back and forth with the server) so I decided against it.
visual example of my application:
(model layer)
M | M
(viewmodel/view layer) VM-V | VM-V | VM-V | VM-V
another example
An example model would be User = {firstName: "first", lastName: "last", ... }
one viewmodel only needs first name, another viewmodel only needs last name
ViewModelA={firstName: app.User.firstName()}ViewModelB={firstName: app.User.lastName()}
Is the only way to do this to define a pub/sub system for Model and Viewmodel changes? Is this even good/maintainable architecture? Am I missing a basic concept here? All advice welcome.
If I read this correctly, there's a lot of questions in here all focused on how to build a MVVM / SPA with Knockout. There are a few things to tackle, as you pointed out. One is how to communicate between viewmodel/view pairs.
Master ViewModel
One way to do that is to have a master viewmodel as the answer from #Tyrsius. Your shell could have a viewmodel that binds more available data. The master viewmodel could orchestrate the child view models, too. If you go this route then you have to be careful to bind the outer shell to the master viewmodel and the inner ones to specific HTML elements in the DOM. The master viewmodel could facilitate the communication between them if need be.
Decoupled View/ViewModel Pairs
Another option is to use viewmodel/view pairs and no master viewmodel. Each view is loaded into a region of the DOM and bound on its own. They act as separate units and are decoupled from one another. You could use pub/sub to then talk between the, but if all you need is a way for the data to be synched through observables, Knockout provides many options. The one I like is to have each viewmodel surface model objects. So a view has a viewmodel which surfaces data (from a model) that is specific for the view. So many viewmodels may surface the same model in different ways. So when a view updates a viewmodel property (that is in a model) it then ripples to any other loaded viewmodel that also uses the same model.
DataContext
Going a bit further, you could create a datacontext module that manages the data in the models. You ask the datacontext for a model (ex: list of customers) and the datacontext checks if it has them cahced already and if not, it goes and gets them from an ajax call. Either way that is abstracted from the view model and models. The datacontext gets the data and returns a model(s) to the viewmodel. This way you are very decoupled, yet you can share the data (your models) via the datacontext.
I could go on and on ... but please tell me if this is answering your question. If not, happy to answer any other specifics.
** Disclaimer: I'm building a Pluralsight course on SPA's (using Knockout and this strategy) :-)
This is a popular field of interest right now, so I expect you will get some better answers, but here goes.
The Model
Yes, you should absolutely have a server-side representation of the data, which is your model. What this is depends on your server, and your database. For MVC3, this is your entity model. For Django or Ruby, your will have defined db models as part of your db setup. This part is up to your specific technology. But agian, yes you should have a model, and the server should absolutely perform data-validation.
The Application (ViewModel)
It is recommended that your views each have their own viewmodel. Your page could then also have a viewmodel, an App Viewmodel if you will, that keeps track of all of them. If you go this route, the app viewmodel should be responsible for switching between the views, and implementing any other application level logic (like hash bashed navigation, another popular single page tool). This hierarchy is very important, but not always simple. It will come down to the specific requirements of your application. You are not limited to one, flat viewmodel. This is not the only possible method.
Ad Hoc Example:
​var ThingViewModel = function(name, data){
this.name = ko.observable(name);
//Additional viewmodel stuffs
};
var AppViewModel = function(initialData){
//Process initial data
this.thing = new ThingViewModel(someName, someData);
};
I am working on a similar project right now, purely for study (not a real world app), that is hosted here on GitHub, if you would like to take a look at some real exmaples. Note, the dev branch is quite a bit ahead of the master branch at the moment. I'm sure it contains some bad patterns (feel free to point them out, I am learning too), but you might be able to learn a few things from it anyway.
I have a similarly complex solution in which I am reworking a WPF application into a web version. The WPF version dealt with complex domain objects which it bound to views by way of presenter models.
In the web version I have implemented simplified and somewhat flattened server-side view models which are translated back and forth from / to domain objects using Automapper. Then those server-side view models are sent back and forth to the client as JSON and mapped into / onto corresponding Knockout view models (instantiable functions which each take responsibility for creating their children with sub-mapping options) using the mapping plugin.
When I need to save / validate my UI, I map all or part of my Knockout view model back to a plain Javascript object, post it as JSON, the MVC framework binds it back to server-side view models, these get Automapped back to domain objects, validated and possibly updated by our domain layer, and then a revised full or partial graph is returned and remapped.
At present I have only one main page where the Knockout action takes place but I anticipate that like you, I will end up with multiple contexts which need to deal with the same model (my domain objects) pulled as differing view models depending on what I'm doing with them.
I have structured the server side view model directories etc in anticipation of this, as well as the structure of my Knockout view models. So far this approach is working nicely. Hope this helps.
During a project i developed a framework (which uses KnockoutJS) which provides decoupled View/ViewModel pairs and allows to instantiate subviews in a view. The whole handling of the view and subview instantiation is provided by the framework. It works like MVVM with XAML in WPF.
Have a look at http://visto.codeplex.com
I am writing a module based javascript website, backed by a Mysql DB.
Each module talks with the DB through PHP.
On the UI, for simplicity, the module on the left will display all relevant rows, with edit(write) functionality. The module on the right display the data from the same DB, with write access too.
So each would affect the other in each update.
I'm told backbone would be a good framework. Then, I have read the todos example, and understand how there are item->itemList, view->viewList, etc...
But now, the question is, how do I apply it to this situation?
Which is an item, a view in this situation?
The module on the left and the module on the right are Views, each of which can be made up of other views.
Within the model don't store a reference to the view (as I've seen done in some of the examples):
this.view = view; //view being passed in as an arg
The reverse (a view storing a reference to a model) is okay. Your views should be doing most of the work, listening to and responding to model events. Thus, in the view initialize method you might:
model.bind("interesting-event", function(){
//the view updates/reacts to the model.
});
Also, never add a model to two collections (just one ever). When a model is assigned to a collection, Backbone sets a reference on the model that points to the owning collection.
Incidentally, the a-model-cannot-belong-to-two-collections issue is the reason why you don't want a model referencing its view. A model can have many views on one screen.
Backbone is perfect for your needs. Start with a very basic version of your app and keep fleshing it out. All the while keep reading about Backbone online. I read everything I could find (there's not a whole lot, not really). The key concept is simply event based programming (much like you'd use in VB or lots of other platforms). It's a lot of trial and error, but you'll make sense of it with practice.
I'm building an extremely JS-heavy web application. I say it's JS-heavy, because the vast majority of the work going on is done on the client (although there is some syncing back and forth to the server using AJAX and XMPP).
This is my first time building something of this scale in pure JS (using jQuery), so I began by organizing my code using MVC in a manner modeled after Rails. For example, if the user clicks a button, a method is called in the Controller object, which pulls some data from the models, and which then passed the data a view function. I do this for pretty much everything, even trivial actions like showing a small popup.
After a few months of this, I feel like I'm not taking full advantage of the language. Should I really be rendering my views as if they are webpages?
It seems like it'd make more sense to break down the views into components, which would be instances of Javascript objects/functions. For example, instead of...
var itemListHTML = '<ul id="item-list"><li>item1</li><li>item2</li></ul>';
jQuery('#container').html(itemListHTML);
...I could instead have...
components.itemList.render();
So here, there's just a component called itemList. Since all the data is stored on the client, these components could instantly access all of the data necessary to create and manage themselves. I imagine I would still use MVC, but there'd be no need for controller actions that are responsible for the entire view. If I want to refresh one part of the UI, I just call whateverComponentControlsThatArea.redraw() and it re-renders itself.
I'm sure someone had done this before. Is there a name for this style of code organization? Any guides or best-practices for how to implement it?
There are a number of javascript MVC frameworks available now
JavaScriptMVC, PureMVC, Sammy.js for example.
Rendering of views or sub-views in normally handled through some kind of templating engine.
JavaScriptMVC has a module EJS, which is modelled on ERB, which I have found quite useful. Templates can be compiled into functions to speed things up for production.
There are other templating solutions too for example John Resig's Micro-Templating and many more
I recommend you use one of these frameworks if it's not too late. I've used JavaScriptMVC for a few projects now and can recommend it (The docs take some getting used to though)
You should really look into jquery.tmpl (http://api.jquery.com/jquery.tmpl/) for creating fast javascript templating ideal for building your view rendering.
A little late to the party, but I've got $0.02 here that I'm not sure what to do with...
Forgetting about (typical) Web-MVC (ie: RailsMVC, et cetera) for a second:
Consider that JavaScript can all be resident in the same place, and that you don't have to worry about figuring out routing and class-instantiating (unless you really want to).
Ideally, from a software point of view, what you want MVC to do is to separate what the user does, from what makes up the content (based on the action), from what makes up the view (based on the action).
There's nothing saying that you can't have multiple views, or even that you can't have a view which contains multiple views (which might use templates, or be functionally generated, and attached to a DOM-node - either is valid).
In a simple pseudo-example, rather than having a flow that looks like:
Action Loads Controller -> Controller Loads Model -> Controller Queries Model -> Model Answers Controller -> Controller Loads View -> Controller Feeds Data to View -> View Sends Page to Controller -> Controller Outputs Page
Why not something like:
Controller Listens for Action (addEventListener) -> Controller Turns Action into State-Logic -> Controller Notifies Model (observer) OR Model Polls Controller -> Model Changes State based on Logic, and Collects / Sorts all Data -> Model Notifies View (observer) OR View Polls Model -> View Changes State based on Logic -> View Renders all Components, based on Data + ViewState (innerHTML OR documentFragment).
It looks a little longer, but in reality, everything is nice and separate.
With the View (or View Manager or however you want to think of it) dictating what windows are on the page, and how each window is made up, and where the data goes, inside of each article, in each window...
...now you have an MVC pattern, but you ALSO have the ability to say:
View["mainpage"] = {
data : { tweets : [{id:...}...]/* et cetera - pushed by Model, not Controller */ },
layout : [ "Header", "Carousel", "Articles", "TwitterFeed", "RSSFeed", "Footer" ],
// if your system is this clean, you could even prototype the content-builders
// rather than defining them in each ViewState - you'd just need layout, then
buildPage : function () {
var page = document.createDocumentFragment();
for (/* everything in this.layout */) {
View.build[this.layout[i]](this.data, page);
}
document.body.appendChild(page);
},
cleanUp : function () { /* fancy or simple DOM cleaning for state-change */ },
// grabs SubView by expected handle (id="tweetfeed" or whatever) and replaces it
// observer functionality, for views to automatically update as data changes
updateView : function (view, newData) { ... },
addData : function (data) { this.data = data; }, // for Observer
/* Observer - if you want to run the WHOLE site with AJAX from index.html
* clean up old (ex:"main") page and build and/or transition new (ex:"media") page
* could be unique for each page, for custom transitions, or just prototype it */
changeState : function (newState, newData) {
View["mainpage"].cleanUp();
View[newState].addData( newData );
View[newState].buildPage();
}
}
And now you've defined your whole main-page.
Of course, it's going to be extra work maintaining not only definitions for your main page, but for every page/section.
...and then, you need to make the functions which will create each sub-view -- but component-based design is EXACTLY what you were asking about.
In essence, for each widget, it will have its own building-logic.
That's what views do - they either have an individual template that gets reused, or they have a function that works the same way every time.
And an atomic view is one where you're dealing with a function that builds 1 item (1 Tweet, 1 Post, 1 Store item) and builds the view for that.
Having a Single_Tweet view post a single-tweet to the page, 20 times in a row would be a bad idea for JS performance.
But having a Single_Tweet view push tweets, in order, into a Tweets array that your Twitter_Feed view puts on the site is A-OK.
Even better is when your Pages are Views, made up of Widgets of Views, made up of Atomic-Units of Views.
And when all of that happens off-DOM (so innerHTML or documentFragment).
And the best would be a Framework where you define pages in this way, but you can also update an individual Widget, based on data-pushes from the Model, whenever you want.
And that's the beauty of AJAX -- old-fashioned MVC can happen, without a Controller that knows everything.
The Controller just holds a list of pressed-keys, the mouse coordinates, a clicked button's intent...
And it tells the Model that something happened.
The Model does everything state/data/data-manipulation (sorting) related, and feeds the new state or data to the view, which takes it all and puts it into HTML, in the order you specify.
That's about it.