I have been playing around with AngularJS, and I am falling in love! We use KnockoutJS pretty extensively in our site, and while I do like KO, I think it is better suited for small enhancements rather than larger things like we do: cart management and a ship estimator, a pretty advanced checkout page, and a school address picker. These all work okay with KO, and honestly, they would probably work much better if they were designed better. Unfortunately this work was initially farmed out to some overseas contractors, and they seem to believe in the anti-KISS pattern, if that even exists…
To begin with, I started on some demos to focus on each task. I created a small ship estimator demo, then I made a small cart demo. Again, due to a really poor design, the ship estimator (which should be the easiest thing with a whopping 3 form fields) is the worse of the 2 in the current implementation. To be fair to KO, I think if the redesign I used for the demo were what we used in our live site, KO would suffice. That being said, Angular just provides more – it is a framework after all, while KO is just a library.
The latest demo is an address form with a school picker – you enter the zip code and a list of matching schools for the zip are displayed in a select list. Once a selection is made, the form fields are populated with the school address details and the fields are set to readonly.
This all works fine, but my co-worker asked if we could then submit the form via a normal HTML form submission. That got me to wondering, so I asked Google. I found a great post on the NG Google Group. The suggestion was to use hidden inputs to store values, and offered a couple ways to do so:
A) (This)
<input type="hidden" name="someName" value="someVal">
becomes
<input type="hidden" ng-init="someName = 'someVal'"
name="someName" value="{someName}}">
This first option … gives you the benefit of having the value in the scope and on the hidden element constantly synchronized.
B) Write a directive for hidden input types that picks up the name and value and inserts it into the scope. This is not too hard:
app.directive('input', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
if ( attrs.type === 'hidden' ) {
scope[attrs.name] = attrs.value;
}
}
};
});
This second option is nice but it won’t allow you to update the hidden field’s value if you plan to do a pure HTML form submission later (although with a little thought and $watch you could probably wire this up).
In our demo code, my co-worker and I opted for the first approach. It winds up being a bit more verbose, but it isn’t too much extra leg work and works well with the 2-way binding to keep the form values up to date.