Web frameworks are a double edged sword. They are, as a rule, bloated, complicated, opinionated and powerful. You can get a lot done, so long as you stick to the framework's "happy path", and while you can wander off and probably make it work, there be dragons. You also run into a lot of developers who, instead of learning the underlying principles, just learn the framework. This means they might not understand broader web development, but can do a lot with Angular.
And then you might have developers who don't understand broader web development or the framework they're using.
Dora has someone on their team which meets that criteria.
The first sign there was a problem was this line in a view object:
<a href class="btn" ng-click="doSomething()" ng-disabled="$ctrl.numFormErrors > 0">save form</a>
First off, ng-disabled
adds the disabled
attribute to the DOM element, which doesn't do anything to a
nchor tags. The goal here is to disable the "save" button if there are validation errors, and already the goal has been missed. However, that's not the weirdest part of this. Angular provides loads of helper variables and functions, including a form.$invalid
which helpfully tells you if there are validation errors. So where is $ctrl.numFormErrors
coming from?
$scope.$watch("form.$error", function(errors) {
$ctrl.numFormErrors = 0;
$ctrl.fieldsWithErrors = [];
_.forEach(errors, function (errs) {
for (var i = 0; i < errs.length; i++) {
if ($ctrl.fieldsWithErrors.indexOf(errs[i].$name) < 0) {
$ctrl.fieldsWithErrors.push(errs[i].$name);
$ctrl.numFormErrors++;
}
}
});
}, true);
Oh, that's simple enough. So much clearer than using the built in form.$invalid
.
If you're not "up" on Angular, and without diving too deep on the mechanics, $scope.$watch
registers a callback: every time form.$error
changes, we invoke this function. In this callback, we clear out our $ctrl.numFormErrors
and $ctrl.fieldsWithErrors
. The keys of errors
are validation failures, like maxlength
and pattern
, so we use the lodash library to forEach
through each of those keys.
The values are arrays of which fields have the given error, so we for
loop across errs
(I guess we didn't want to use lodash again?). If we haven't already tracked an error for the field with this $name
, we add it to our array and increment the numFormErrors
field.
Now, every time the user edits the form, we'll have a list of exactly which fields are invalid, and an exact count about how many there are. That's not something Angular makes obvious, so we've accomplished something, right?
Well, the only problem is that this code never actually uses $ctrl.fieldsWithErrors
and it only ever checks if $ctrl.numFormErrors > 0
, so no- we didn't need to do any of this.
Dora threw out the $watch
and just replaced the a
nchor with a button
done the "Angular" way:
<button class="btn" ng-click="doSomething()" ng-disabled="form.$invalid">save form</button>