Skip to content

Commit b7f33f4

Browse files
refact(chapter-10): even more simplification of the field directive
1 parent 62b28f1 commit b7f33f4

File tree

9 files changed

+28
-79
lines changed

9 files changed

+28
-79
lines changed

1820EN_10_Code/04_field_directive/directive.js

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ angular.module('field-directive', ['input.html', 'textarea.html', 'select.html']
5959
}
6060

6161
// Extract the label and validation message info from the directive's original element
62-
var messageMap = getValidationMessageMap(element);
62+
var validationMessages = getValidationMessageMap(element);
6363
var labelContent = getLabelContent(element);
6464

6565
// Clear the directive's original element now that we have extracted what we need from it
@@ -71,7 +71,7 @@ angular.module('field-directive', ['input.html', 'textarea.html', 'select.html']
7171
// Set up the scope - the template will have its own scope, which is a child of the directive's scope
7272
var childScope = scope.$new();
7373
// Attach a copy of the message map to the scope
74-
childScope.$messageMap = angular.copy(messageMap);
74+
childScope.$validationMessages = angular.copy(validationMessages);
7575
// Generate an id for the field from the ng-model expression and the current scope
7676
// We replace dots with underscores to work with browsers and ngModel lookup on the FormController
7777
// We couldn't do this in the compile function as we need to be able to calculate the unique id from the scope
@@ -122,31 +122,4 @@ angular.module('field-directive', ['input.html', 'textarea.html', 'select.html']
122122
};
123123
}
124124
};
125-
})
126-
127-
// A directive to bind the interpolation function of a validation message to the content of an element.
128-
// Use it as a attribute providing the validation key as the value of the attribute:
129-
// <span bind-validation-message="required"></span>
130-
.directive('bindValidationMessage', function() {
131-
return {
132-
link: function(scope, element, attrs) {
133-
var removeWatch = null;
134-
// The key may be dynamic (i.e. use interpolation) so we need to $observe it
135-
attrs.$observe('bindValidationMessage', function(key) {
136-
// Remove any previous $watch because the key has changed
137-
if ( removeWatch ) {
138-
removeWatch();
139-
removeWatch = null;
140-
}
141-
if ( key && scope.$messageMap[key] ) {
142-
// scope.$messageMap[key] returns an interpolation function.
143-
// Watch the value of calling this function with the current scope.
144-
// Update the contents of the current element if the message changes
145-
removeWatch = scope.$watch(scope.$messageMap[key], function(message) {
146-
element.html(message);
147-
});
148-
}
149-
});
150-
}
151-
};
152-
});
125+
});

1820EN_10_Code/04_field_directive/directive.spec.js

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -107,50 +107,22 @@ describe('field directive', function () {
107107
expect(innerScope.$fieldErrors).toEqual(['maxlength']);
108108
});
109109

110-
describe('$messageMap', function() {
110+
describe('$validationMessages', function() {
111111
it('contains all specified validator messages', function() {
112112
var element = $compile('<field ng-model="x.y"><validator key="x"></validator><validator key="y"></validator></field>')(scope);
113113
scope.$digest();
114114
var innerScope = element.find('input').scope();
115-
expect(innerScope.$messageMap).toBeDefined();
116-
expect(innerScope.$messageMap.x).toEqual(jasmine.any(Function));
117-
expect(innerScope.$messageMap.y).toEqual(jasmine.any(Function));
115+
expect(innerScope.$validationMessages).toBeDefined();
116+
expect(innerScope.$validationMessages.x).toEqual(jasmine.any(Function));
117+
expect(innerScope.$validationMessages.y).toEqual(jasmine.any(Function));
118118
});
119119
it('contains interpolation functions', function() {
120120
var element = $compile('<field ng-model="x.y"><validator key="x">X{{x}}Y</validator><validator key="y">Y{{y}}Z</validator></field>')(scope);
121121
scope.$digest();
122122
var innerScope = element.find('input').scope();
123-
expect(innerScope.$messageMap.x({x: 10})).toEqual('X10Y');
124-
expect(innerScope.$messageMap.y({y: 'xxx'})).toEqual('YxxxZ');
123+
expect(innerScope.$validationMessages.x({x: 10})).toEqual('X10Y');
124+
expect(innerScope.$validationMessages.y({y: 'xxx'})).toEqual('YxxxZ');
125125
});
126126
});
127127
});
128-
});
129-
130-
describe('bind-validation-message directive', function() {
131-
var scope, $compile;
132-
133-
beforeEach(module('field-directive'));
134-
beforeEach(inject(function ($rootScope, _$compile_) {
135-
scope = $rootScope;
136-
$compile = _$compile_;
137-
}));
138-
139-
it('updates the content of the element based on the validation message info in the field controller', function() {
140-
var element = $compile(
141-
'<field ng-model="x">' +
142-
' <label>Label 1</label>' +
143-
' <validator key="xx">Error {{$fieldLabel}}</validator>' +
144-
'</field>')(scope);
145-
scope.$digest();
146-
// There should be no error message yet
147-
expect(element.find('span').text()).toBe('');
148-
var innerScope = element.find('input').scope();
149-
// Set the error for validation key xx
150-
innerScope.$field.$setValidity('xx', false);
151-
innerScope.$field.$setViewValue('some value to make the field $dirty');
152-
scope.$digest();
153-
// There should now be an error message
154-
expect(element.find('span').text()).toBe('Error Label 1');
155-
});
156128
});

1820EN_10_Code/04_field_directive/index.html

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,21 @@
2020
<label>Labels which can <span ng-repeat="i in [0,1]">{{i}}</span> contain directives</label>
2121
</field>
2222

23-
<field ng-model="myModel.myText" type="text" field-label="My {{'Text'}}" required="true">
23+
<field ng-model="myModel.myText" type="text" required="true">
24+
<label>My {{'Text'}}</label>
2425
<validator key="required">My Text is required</validator>
2526
</field>
2627

27-
<field ng-model="myModel.myBigText" template="textarea.html" field-label="My Big Text" ng-maxlength="5" ng-minlength="2" required="true">
28+
<field ng-model="myModel.myBigText" template="textarea.html" ng-maxlength="5" ng-minlength="2" required="true">
29+
<label>My Big Text</label>
2830
<validator key="maxlength">{{$fieldLabel}} must be less than 5</validator>
2931
<validator key="minlength">{{$fieldLabel}} must be greater than 2</validator>
3032
<validator key="required">{{$fieldLabel}} must be greater than 2</validator>
3133
</field>
3234

33-
<field ng-model="myModel.choice" template="select.html" field-label="Choose something" ng-options="x for x in ['A','B', 'C']"></field>
35+
<field ng-model="myModel.choice" template="select.html" ng-options="x for x in ['A','B', 'C']">
36+
<label>Choose something</label>
37+
</field>
3438

3539
<pre>{{myModel | json}}</pre>
3640
</form>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div class="control-group" ng-class="{'error' : $field.$invalid && $field.$dirty, 'success' : $field.$valid && $field.$dirty}">
2-
<label class="control-label" >{{label}}</label>
2+
<label class="control-label"></label>
33
<div class="controls">
44
<input>
5-
<span class="help-inline" ng-repeat="error in $fieldErrors" bind-validation-message="{{error}}"></span>
5+
<span class="help-inline" ng-repeat="error in $fieldErrors">{{$validationMessages[error](this)}}</span>
66
</div>
77
</div>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
angular.module("input.html", []).run(["$templateCache", function($templateCache) {
22
$templateCache.put("input.html",
33
"<div class=\"control-group\" ng-class=\"{'error' : $field.$invalid && $field.$dirty, 'success' : $field.$valid && $field.$dirty}\">" +
4-
" <label class=\"control-label\" >{{label}}</label>" +
4+
" <label class=\"control-label\"></label>" +
55
" <div class=\"controls\">" +
66
" <input>" +
7-
" <span class=\"help-inline\" ng-repeat=\"error in $fieldErrors\" bind-validation-message=\"{{error}}\"></span>" +
7+
" <span class=\"help-inline\" ng-repeat=\"error in $fieldErrors\">{{$validationMessages[error](this)}}</span>" +
88
" </div>" +
99
"</div>");
1010
}]);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div class="control-group" ng-class="{'error' : $field.$invalid && $field.$dirty, 'success' : $field.$valid && $field.$dirty}">
2-
<label class="control-label">{{label}}</label>
2+
<label class="control-label"></label>
33
<div class="controls">
44
<select></select>
5-
<span class="help-inline" ng-repeat="error in $fieldErrors" bind-validation-message="{{error}}"></span>
5+
<span class="help-inline" ng-repeat="error in $fieldErrors">{{$validationMessages[error](this)}}</span>
66
</div>
77
</div>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
angular.module("select.html", []).run(["$templateCache", function($templateCache) {
22
$templateCache.put("select.html",
33
"<div class=\"control-group\" ng-class=\"{'error' : $field.$invalid && $field.$dirty, 'success' : $field.$valid && $field.$dirty}\">" +
4-
" <label class=\"control-label\">{{label}}</label>" +
4+
" <label class=\"control-label\"></label>" +
55
" <div class=\"controls\">" +
66
" <select></select>" +
7-
" <span class=\"help-inline\" ng-repeat=\"error in $fieldErrors\" bind-validation-message=\"{{error}}\"></span>" +
7+
" <span class=\"help-inline\" ng-repeat=\"error in $fieldErrors\">{{$validationMessages[error](this)}}</span>" +
88
" </div>" +
99
"</div>");
1010
}]);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<div class="control-group" ng-class="{'error' : $field.$invalid && $field.$dirty, 'success' : $field.$valid && $field.$dirty}">
2-
<label class="control-label">{{label}}</label>
2+
<label class="control-label"></label>
33
<div class="controls">
44
<textarea></textarea>
5-
<span class="help-inline" ng-repeat="error in $fieldErrors" bind-validation-message="{{error}}"></span>
5+
<span class="help-inline" ng-repeat="error in $fieldErrors">{{$validationMessages[error](this)}}</span>
66
</div>
77
</div>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
angular.module("textarea.html", []).run(["$templateCache", function($templateCache) {
22
$templateCache.put("textarea.html",
33
"<div class=\"control-group\" ng-class=\"{'error' : $field.$invalid && $field.$dirty, 'success' : $field.$valid && $field.$dirty}\">" +
4-
" <label class=\"control-label\">{{label}}</label>" +
4+
" <label class=\"control-label\"></label>" +
55
" <div class=\"controls\">" +
66
" <textarea></textarea>" +
7-
" <span class=\"help-inline\" ng-repeat=\"error in $fieldErrors\" bind-validation-message=\"{{error}}\"></span>" +
7+
" <span class=\"help-inline\" ng-repeat=\"error in $fieldErrors\">{{$validationMessages[error](this)}}</span>" +
88
" </div>" +
99
"</div>");
1010
}]);

0 commit comments

Comments
 (0)