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
Related
Note: Sorry for the length of the post, but the reason I decided not to break it down in separate questions was because I find these issues hard to address without a complex problem like this. I am dazzled, and a bit afraid, that I'm trying to force Angular to do stuff for me which is not the 'Angular way'. Any advice would be highly appreciated, and would probably get me on the right track with Angular.
My problem is as follows:
I have a dynamically generated form, controlled by myFormCtrl. I want to go extremely modular: I want to use it whenever and wherever. This means, that sometimes I'll need to put it somewhere as-is, sometimes I need to nest forms dynamically (like when I change a form value, and other sub-form appears), or control two separate forms as one in a view by a parent controller, with one 'Save' button for both. The myFormCtrl uses $scope.type_id and $scope.rowid to know, which record should it display from the database. The records are then Ajax-fetched by a service, and saved under the myFromCtrl's $scope.formItems. When saved, the form sends back data to the server (via service) with the type_id and scope credentials, so the restful api knows where to put the record.
In theory that would be really easy to do in Angular.js.
It definitely would be in every object-orientated language: The parent class could call a public method of getFormValues() of myFormCtrl. Now that can't be done in Angular: parent can't read children's scope.
For me, it seems, that this is not a simple 'how to communicate between controllers' issue. I know that the answer to that question is services, events, scope inheritance.
Also, a number of other problems seem to emerge from each solution I found sofar.
So I have a myFormCtrlBase class, which does basic stuff, and other more advanced classes extend this one. I also have a formControls.html, and a formLayout.html partial. The first contains an ng-switch, and gives the appropriate input element based on $scope.formItem.controltype, the second has the html layout of a common form, ng-including formControls.html at the right places. It utilizes ng-repeat="formItem in formItems", so that's where formControls.html's $scope.formItem comes from.
When I want the form to have a different layout for example, I create a customFormLayout.html partial ng-controlled by the myFormCtrl class.
First question: what if my form layout can't be put in an ng-repeat?
Like when form elements need to be placed scattered across the page, or form layout is not something which could be fit in an ng-repeat loop. my formControls.html still expects a $scope.formItem to work with. Easy OO solution: parent puts formItem in child's scope.
My solution: I created a <formItemScopeChanger formItemScope="formItems[1]"> directive which gets formItems[1] as an attribute, and turns it to $scope.formItem variable. This solutions feels messy: directives are not meant to be used like this. Doesn't seem very Angulary. Is this really the best solution?
Second question: Is ng-init really that evil?
Say, form is not put in the view by $routeProvider, but in a custom partial: rent-a-car.html. Here, I want to have a form where the user can select a car, and an other form, where I get his contacts. The two forms work with different $scope.type_id's, so there need to be two different forms:
<h1>Rent a car!</h1>
<div ng-controller="myFormCtrl" ng-init="type_id='rentOrder'">
<div ng-include="'formLayout.html'"></div>
</div>
<h2>Your contact information</h2>
<div ng-controller="myFormCtrl" ng-init="type_id='User';rowid='{{userData.rowid}}'">
<div ng-include="'formLayout.html'"></div>
</div>
Angular docs sais, that the only appropriate use of ng-init is when aliasing ng-repeat values. I don't see what the problem is with the example above - it is still the cleanest solution, isn't it?
I use the same technique with nested forms - I put a controller in with a template, initialized from the html by ng-init, and shown/hidden with an ng-if condition.
BTW, this is the only real initialization technique I found beside writing a new controllers (extending myFormCtrlBase). In an OO language, parent would write into the child's scope and then initialize it.
Perhaps my approach is influenced by my previously used languages and programming techniques, and is absolutely wrong.
Some would say, 'get init values from parent scopes!', but I can't seem to understand how that would be safe and efficient. I'd need to do $scope.type_id=($scope.type_id || $routeParams.type_id) with every scope property, which is first: really not nice to look at, second: is risky. Maybe this is a single form in a simple template, but somewhere in the scope hierarchy, there is a possibility, that it will find a completely different type_id. Perhaps it will be a completely different controller's type_id.
I don't see how using '.'-s in my scope variables would help. I has the same risk as I see it.
Third question: how to handle rentACar.html submission?
When hitting a Save button on my rentACar.html page, the rentACarCtrl (the controller in charge of the model of the view) should somehow retrieve the values of the two forms, and handle the validation and submission. I can't seem to understand how the common mantra 'controllers communicate through services' would be applicable here. A service for only to these two forms?
Am I on the right track? Every one of these solutions seem quirky. I feel lost :)
+ 1 question: Even after all this hassle, I can't seem to find a good reason why Angular wouldn't let parents call children's public stuff. Is there a good reason? Most of the above problems would have an easy answer in every true OO js framework.
You need to think about how you would test the logic of each of these components. Ask yourself how each of these 'features' work in isolation.
A few tips to help get you back on track:
Try and say away from a 'base' controller, I have hit many dead ends with scope inheritance, the logic gets muddled and hard to follow. Also this affects testing, because you find yourself having to stand up more objects than should be necessary for a test
Favor a singleton (angular service) for shared state over scope inheritance (a parent controller)
Create a directive and bind to the shared services state before using ng-include (prefer interacting with a service over scope inheritance)
Use an event pattern when another service or controller needs to now about events triggered from directives. A shared service (state) can listen for those events
What your asking is quite complex and I would like to help, Try to focus on one feature at a time and provide some code, I can show you how to use a shared service and the event pattern once you provide some examples
Also, taking a test first approach will often reveal the best 'Angular Way' of doing things.
Thanks to Mark-Sullivan, and a lot of work, trial-and-error attempts, the whole thing has boiled down to this. I'd like to get feedback from Mark, and other Angular gurus about this. What do you think?
You don't do class/prototypical inheritance in Angular.js. It is hard to test, and thats a big problem. For those, who are looking for 'inheritance' in Angular, I recommend this:
Your base class is the controller. The controller is an abstract model anyways, so it is perfect for that purpose. Use a $scope.init() function in your controller, but don't call it from there!
If you want to 'extend' your controller's functionality, use directives. In you directive link() function, call the controller's $scope.init(). (when compiling, angular runs controllers first, and directive link functions after). If scope had a $scope.name='base', in the directive link you will be able to redefine $scope.name=child, and after that, run $scope.init().
But wait! But this only allows a single-level inheritance. - Yes, thats true. But if you are looking for multilevel inheritance, you should use Services.
Multilevel inheritance is nothing else, but sharing the same code in a hierarchical class structure. For this purpose, use Services, and throw in these services with the dependency injector into your directives. Soo easy. This should be easy to accomplish, easy to understand, and tests run smooth.
Directives are very powerful tools, because you can dynamically combine partials with controllers.
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 ;-)
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.
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!
After dabbling with javascript for a while, I became progressively convinced that OOP is not the right way to go, or at least, not extensively. Having two or three levels of inheritance is ok, but working full OOP like one would do in Java seems just not fitting.
The language supports compositing and delegation natively. I want to use just that. However, I am having trouble replicating certain benefits from OOP.
Namely:
How would I check if an object implements a certain behavior? I have thought of the following methods
Check if the object has a particular method. But this would mean standardizing method names and if the project is big, it can quickly become cumbersome, and lead to the java problem (object.hasMethod('emailRegexValidatorSimpleSuperLongNotConflictingMethodName')...It would just move the problem of OOP, not fix it. Furthermore, I could not find info on the performance of looking up if methods exist
Store each composited object in an array and check if the object contains the compositor. Something like: object.hasComposite(compositorClass)...But that's also not really elegant and is once again OOP, just not in the standard way.
Have each object have an "implements" array property, and leave the responsibility to the object to say if it implements a certain behavior, whether it is through composition or natively. Flexible and simple, but requires to remember a number of conventions. It is my preferred method until now, but I am still looking.
How would I initialize an object without repeating all the set-up for composited objects? For example, if I have an "textInput" class that uses a certain number of validators, which have to be initialized with variables, and a class "emailInput" which uses the exact same validators, it is cumbersome to repeat the code. And if the interface of the validators change, the code has to change in every class that uses them. How would I go about setting that easily? The API I am thinking of should be as simple as doing object.compositors('emailValidator','lengthValidator','...')
Is there any performance loss associated with having most of the functions that run in the app go through an apply()? Since I am going to be using delegation extensively, basic objects will most probably have almost no methods. All methods will be provided by the composited objects.
Any good resource? I have read countless posts about OOP vs delegation, and about the benefits of delegation, etc, but I can't find anything that would discuss "javascript delegation done right", in the scope of a large framework.
edit
Further explanations:
I don't have code yet, I have been working on a framework in pure OOP and I am getting stuck and in need of multiple inheritance. Thus, I decided to drop classes totally. So I am now merely at theoretical level and trying to make sense out of this.
"Compositing" might be the wrong word; I am referring to the composite pattern, very useful for tree-like structures. It's true that it is rare to have tree structures on the front end (well, save for the DOM of course), but I am developing for node.js
What I mean by "switching from OOP" is that I am going to part from defining classes, using the "new" operator, and so on; I intend to use anonymous objects and extend them with delegators. Example:
var a = {};
compositor.addDelegates(a,["validator", "accessManager", "databaseObject"]);
So a "class" would be a function with predefined delegators:
function getInputObject(type, validator){
var input = {};
compositor.addDelegates(input,[compositor,renderable("input"+type),"ajaxed"]);
if(validator){input.addDelegate(validator);}
return input;
}
Does that make sense?
1) How would I check if an object implements a certain behavior?
Most people don't bother with testing for method existance like this.
If you want to test for methods in order to branch and do different things if its found or not then you are probably doing something evil (this kind of instanceof is usually a code smell in OO code)
If you are just checking if an object implements an interface for error checking then it is not much better then not testing and letting an exception be thrown if the method is not found. I don't know anyone that routinely does this checking but I am sure someone out there is doing it...
2) How would I initialize an object without repeating all the set-up for composited objects?
If you wrap the inner object construction code in a function or class then I think you can avoid most of the repetition and coupling.
3) Is there any performance loss associated with having most of the functions that run in the app go through an apply()?
In my experience, I prefer to avoid dealing with this unless strictly necessary. this is fiddly, breaks inside callbacks (that I use extensively for iteration and async stuff) and it is very easy to forget to set it correctly. I try to use more traditional approaches to composition. For example:
Having each owned object be completely independent, without needing to look at its siblings or owner. This allows me to just call its methods directly and letting it be its own this.
Giving the owned objects a reference to their owner in the form of a property or as a parameter passed to their methods. This allows the composition units to access the owner without depending on having the this correctly set.
Using mixins, flattening the separate composition units in a single level. This has big name clash issues but allows everyone to see each other and share the same "this". Mixins also decouples the code from changes in the composition structure, since different composition divisions will still flatten to the same mixed object.
4) Any good resources?
I don't know, so tell me if you find one :)