Guidelines for models in MVVC pattern (specifically using knockout.js) - javascript

This is a general question, but I'd love some feedback. I'm new to working in the MVVC paradigm, and I'm finding it's a perfect fit for my SPA that is 90% about rendering data in different forms (IE very little user manipulation of the data).
But I'm a little confused on where to put formatting or "cleansing" of data between the model and the model-view. My general feeling is that my model-view should have only knockout or jquery specific code that is concerned with updating the view. But some of the formatting seems a little too view-specific to go in the model. For example, if I'm just changing strings to make them more "user friendly" would you put that in the model or the view-model? I'm seems like it's too much user-centric/page-centric knowledge for the model, and yet too much domain knowledge for the view-model.
I understand there's no hard and fast rules, but just wondering what the best guidelines are for situations like this.

The view-model can be thought of as the model-of-the-view. In other words, it is quite specific to the view which it backs. Whilst it is possible to have multiple views bound to the same view model, it is much more common to have a one-to-one correlation between view-models and their respective view.
To answer your question, there is nothing wrong with having highly specialised, view-centric behaviour within the view-model. This includes formatting logic. For example, your model might expose a price as a numeric value, "23.34". If your view displays this as a currency, your view-model would adapt this property in order to format it for viewing, "£23.34".
Finally, the pattern is Model-View-ViewModel (MVVM), not MVVC!

Related

Can event-handling be removed from KnockoutJS models and views?

I've been using KnockoutJS for some time now, mainly on small-to-medium sized projects. However, I'm now working on a very large project with many different views of the same data. For example, a product may be displayed to the customer, allowing them to add products to their shopping cart, and also to an administrator, allowing them to edit the product name, price and available stock. I want to be able to use the same model in both cases, but designing a solution with KnockoutJS is proving difficult. Specifically, I am having two issues:
I want to be able to re-use certain "view" functionality without repeating myself. For example, in both the customer- and administrator- view of products, clicking the product thumbnail displays the product image in fullscreen. Instead of each view containing the same verbose binding code (e.g., <img data-bind="event:{click:function codeToZoom(){}}"/> in both views), I can move the binding information to the model itself. So the above becomes <img data-bind="event:imageEvents()"/>. However, doing the above forces me to include code that responds to user input in my model, which violates the single-responsibility principle - e.g., the model is reponsible for business logic, not responding to user input. If I decided I wanted an administrator clicking the thumbnail to open an "Upload New Image" dialog, then I'd need to implement a imageEventsForAdministrator() function.
I've asked people how they deal with the above, and their answer has been "Write two different models." This sounds good until you realise that a product has a lot of embedded logic, and writing two different models forces you to duplicate that logic. So:
According to KnockoutJS, what is the recommended approach for separating business logic from responding to events/user-input?
Your post is interesting and understandable... yet really rather broad for Stack Overflow.
To answer some of your more specific subquestions though:
I want to be able to re-use certain "view" functionality without repeating myself.
There are two typical constructs for tackling this issue:
Use templates to do so. Knockout will keep the template as a "prototype" view, and instantiate new instances (and clean up) as needed.
Load view html dynamically as "partial views" if you will, and use the appropriate applyBindings overload to render those bits only when needed.
For example, [...] clicking the product thumbnail displays the product image in fullscreen [...] <img data-bind="event:{click:function codeToZoom(){}}"/> in both views
Well, there's several options here. I find that if you want you can actually de-duplicate code as much as theoretically possible. First, you can usually do this:
<img data-bind="event:{click: myHandler}"/>
And you can use some kind of prototypical or classical inheritance on your view models to make sure myHandler is only defined once.
Again, if you find yourself repeating the <img... bit: use KO templates.
Moving on:
This sounds good until you realise that a product has a lot of embedded logic, and writing two different models forces you to duplicate that logic.
In that case you're probably violating the SRP. You probably need to take that logic out of your view models and place it somewhere else (e.g. in controllers, DALs, etc.). But that topic is really broad, our sister site has an entire tag dedicated to it.
Finally, you ask:
According to KnockoutJS, what is the recommended approach for separating business logic from responding to events/user-input?
KnockoutJS recommends no particular approach.
That is, KO is an MVVM library, and as such does nudge you in a certain direction, but it doesn't really force you to take any particular approach with this. It's really up to you to write and structure infrastructure and code for common business logic, think up a good inheritance strategy or something similar, etc.
So it's up to you.
As a footnote, if you haven't already, I'd recommend running through some AngularJS tutorials as well. It has MVVM style bindings, but it is IMO more opinionated about how to solve the problems you're facing. (This is not advice to switch; merely advice to find inspiration in KO-alternatives.)

Backbone.js - How to handle multiple models with the same id and type? Or how to avoid that situation

I've been running into a few situations recently, where I have multiple views on the page that need to be backed by a single model. This way, just by modifying the model, all of the relevant views will automatically update their appearance. The problem is, in order to achieve this atm, I would need to write code that actively seeks out these models. I will occasionally get lucky and have a model provided to me through an event handler, but usually this isn't the case. I'm looking for a good way to have a single instance of a model on the page at a time, and then just references to that model everywhere else. How do people commonly handle this need? Backbone-relational handles it by keeping a central store using lawnchair.js, and I have heard of people using a single global collection to keep a registry of all of the models.
Short Answer:
One model shared by multiple views (which you could call "duplicate models") is actually a perfectly valid (and useful) Backbone pattern; it's not a problem at all. From what I can tell the problem here is that it's difficult to get that model in to the multiple views, and therefore I'd suggest solving that instead.
Longer Answer:
The problem with passing a model to multiple views is that it inherently couples views together (in order to provide that shared model to each view, the parent view needs to also have that model, as do any "in between" views). Now as programmers we've been taught to keep things as encapsulated as possible, so coupling views might seem "wrong" at first. However, couple views is actually desirable: the key thing is to properly limit which views are coupled.
#Shauna suggested an excellent rule of thumb for this: "a view only cares about itself and creating its children." If you follow this rule, the coupling between your views won't become problematic, and you'll be able to create flexible, maintainable code (far more maintainable than if you were to use global variables, as then you'd really lose encapsulation).
In light of all that, let's examine a quick example. Let's say you have views A, B, and C that all use model X, but you're building A, B and C in totally different places in the code (making it difficult to share X between them).
1) First, I'd look at why A, B, and C are being built in such different spots, and see if I can't move them closer together.
2) If they have to be built so far apart, I'd then look at whether they have something in common I can exploit; for instance, do all those spots all share some related object? If so, then maybe we can put X on that object to share it with all our views.
2) If there's no connection either in code placement or in common variables between A, B, and C, then I'd have to ask "should I really be sharing a model between them at all?"
Boring Story About Author:
When I first started using Backbone, I would often find myself arguing with my co-workers because I wanted to make global variables, and they were firmly against them. I tried to explain to them that if I couldn't use globals I'd have to pass models from view A to view B to view C to view D to view E, when only E would actually need that model. Such a waste!
Except (as I've since learned), I was wrong. Globals are a horrible idea, at least from a maintainability standpoint. Once you start using them, you quickly have no idea what code is affecting what, because you lose the encapsulation you'd normally have between views that use that global variable. And if you're working on a meaningfully large project (ie. one that is worth using Backbone for) encapsulation is one of the only ways to keep your code sane.
Having used Backbone a lot in the time in between, I now firmly believe that the right answer is to pass your model to your view as you create it. This might mean passing models between intermediary views that don't directly use them, but doing that will give you much better, more maintainable code than if you passed models around via globals. As awkward as it may feel at first, passing the models in to the views when you create them is proper practice.
Once you get more familiar with Backbone you will likely find that you only rarely need to pass a model through more than one intermediary view. In fact, you'll likely notice that whenever you find yourself having to pass a model between more than one view that you've detected a "code smell", and that the real issue is that your code needs refactoring.
But as with everything else on Stack Overflow, your mileage may vary ;-)

Javascript MVVM design patterns - how to track dirty state and who should do Ajaxing?

I'm part way through a pretty complex Knockout.js app using the mapping plugin to work with a deep object graph which closely mirrors server side domain objects. I've been refining my patterns as I go to something which works pretty well for my own slightly awkward context but I'd like to know if it's a good / bad overall way to approach MVVM Javascript.
Essentially my page pattern is to have a revealing module function which acts a bit like a controller - it owns the hierarchy of view models and is responsible for detecting changes, Ajaxing changes to the server and using the mapping plugin to update its view model graph with any flow-on changes which may come back in the response as JSON. I've done it this way because my domain is such that a small change in one part of the graph, when validated on the server, may result in changes / removals in distant parts of the graph. When this happens I need a common point at which to re-map the changes, present message dialogs to the user, etc.
All of my view models are instantiable functions and I've designed it so that they know nothing about the page they're used in, or the server (i.e. they don't do their own Ajaxing). The constructor of each view model creates its children via mapping options and each level is passed a reference to its parent. I've implemented a generic dirty flag which most of the view models use, and when a change occurs they pass a reference to themselves up the chain to a "dirty view model" observable at the top, which the module is subscribed to. I know this sounds a bit odd but it seemed the best way to approach it because items at each level are constantly being added and removed so I can't statically subscribe to properties at initialization time. And I don't want to keep removing and re-adding subscriptions each time I re-map my graph (which can get quite big).
From a pure efficiency point of view this isn't the best. The simplest way would be that each view model directly calls a function in the module when it needs to, but that type of coupling has to be wrong. Or I could pass in a reference to the module (or its relevant function) to each view model constructor, and the view model calls that, a bit like Javascript dependency injection. But that just seems too abstract. This is complex enough as it is.
Should I be looking at a higher level framework such as Backbone to sit on top of all this? Is injecting the module reference really too abstract? Or does this way of structuring things basically make sense as it is? I'm keen to hear from anyone who has worked on similarly challenging scenarios as to how you progressed and refined your patterns.
EDIT: I should have clarified that for various reasons, this app works in "save as you go" mode, whereby a change at a given level causes an immediate discrete Ajax post of just that one view model (not including its children) to be sent to the server (which may return a result which represents a change to just about anything else). Despite this annoying need for constant Ajaxing as opposed to pure client side action, Knockout.js has still made my app WAY more elegant, maintainable and scalable than my MVC apps of Olde.
Decoupling your viewmodels and reducing references can be achieved with a pub/sub model, like the one Ryan Niemeyer discusses here.
Ryan also made a Dirty flag for viewmodels, which can be found here.

Knockout/MVVM Design Concern

I am struggling with a problem that keeps cropping up when working with the KnockoutJS framework and MVVM in general. There are times when a property on a specific item in a collection changes and because of that change, I need to affect all the other items in that same collection. In all languages and patterns, an object isn't supposed to "know" anything about the collection it's in, but I find myself needing to break that rule often to get certain kinds of logic to work.
I have created a contrived example of what I'm talking about to demonstrate the hacky sort of way I've been solving this problem. I'm hoping someone with more experience can weigh in and show me the better way to do this.
JSFiddle Contrived Example
I don't know whether this is the "recommended" approach, but I will offer my advice of how I would tackle this issue. I am not a MVVM expert (though I've written quite a few KnockoutJS apps), but I think some OOP principles will be more than enough to help here.
So first let's discuss the current state of things...
Your approach, as you correctly observed (knockout pun unintentional!), is not ideal - the Person objects are aware not just of their siblings (even if indirectly via a subscription) but also the parent object to which they are subscribing - Your Person type is subscribed to changes on the parent. Not only does this make your Person object unusable outside of this scenario, it also gives each instance too much responsibility (violating the Single Responsibility Principle) and each instance is subscribed to changes on every other instance, which is of course wasteful!
So what's the solution?
To me the ideal place to put this kind of logic is on your parent object (i.e. your view model). Your view model already has knowledge of it's child objects, so why not put the functionality there? This would make your Person type reusable elsewhere (OK so it has observables, so it's tied to KO at the moment, but this can be overcome with the Mapping plugin) and relieves it of the responsibility of managing its siblings.
But still this means that you have tight coupling between parent and child - not what we want in OOP! To overcome this, you can adopt a pub/sub (observer) pattern and have your Person type publish a message whenever something changes, then you can let a subscriber (e.g. you view model) decide how to respond to this event. You need not necessarily use knockout's pub/sub offerings either, any pub/sub implementation will do. Though you may as well take advantage of what KO offers, so I would point you in the direction of these extensions/helpers to ease things a little: http://www.knockmeout.net/2012/05/using-ko-native-pubsub.html
Hope I've been of help :)
Unless I misunderstood your scenario, you could use computed observables that update on the fly automatically.
First, I figured the 'underage' property flag for each person would just be a calculation of their age compared to a min. age. e.g. 19.
Second, You can also use a computed observable to do an aggregate flag for all users.
Lastly, I wouldn't necessarily agree that this is a parent/child relationship. These are just properties of the view model specific to the page.
Check out this example that uses computed's for both cases.
http://codepen.io/anon/pen/ufKCo

Am I deviating from MVC if I have a Backbone View without a Model?

I have a couple of Views which do not seem to have logically coherent Models. I can still try to create dummy Models for these (and properly have routers as well) but it seems unnatural to me.
So is having a Backbone View without a corresponding Model an anti-pattern?
What do the experts say on this?
the various components of backbone play well with each other, but there's no need for them to always go together.
i very regularly have models with no views, and views with no models. each of the pieces of a backbone app can be used in many different ways to facilitate what you need your app to do.
I don't think it is specifically an anti-pattern. If all you are trying to do is encapsulate view behavior, it might make sense to write a view and attach it to an element. It might not have any business logic or persistable data... it might just be a View that encapsulates view behavior (like something that manages the state of an element based on events). In that case, there is no need for a model.
On the other hand, if you are managing a bunch of variables (persistable or not) and any type of business logic, then it makes sense to break that out into a model.
If you are considering adding a dummy model or any other logic/code to make the architecture fit a pattern, that should be a red herring. The pattern should be there to assist you in designing logically well organized predictable code.

Categories

Resources