Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 3e42b22

Browse files
refact(input): split input.js into smaller files
The input.js file is unnecessarily large, containing many directives including the vast `ngModel`. This change moves ngModel and a few other directives into their own files, which will make maintenance easier.
1 parent deb3cb4 commit 3e42b22

File tree

8 files changed

+3222
-3190
lines changed

8 files changed

+3222
-3190
lines changed

angularFiles.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ var angularFiles = {
5353
'src/ng/directive/form.js',
5454
'src/ng/directive/input.js',
5555
'src/ng/directive/ngBind.js',
56+
'src/ng/directive/ngChange.js',
5657
'src/ng/directive/ngClass.js',
5758
'src/ng/directive/ngCloak.js',
5859
'src/ng/directive/ngController.js',
@@ -61,6 +62,8 @@ var angularFiles = {
6162
'src/ng/directive/ngIf.js',
6263
'src/ng/directive/ngInclude.js',
6364
'src/ng/directive/ngInit.js',
65+
'src/ng/directive/ngList.js',
66+
'src/ng/directive/ngModel.js',
6467
'src/ng/directive/ngNonBindable.js',
6568
'src/ng/directive/ngPluralize.js',
6669
'src/ng/directive/ngRepeat.js',
@@ -70,7 +73,8 @@ var angularFiles = {
7073
'src/ng/directive/ngTransclude.js',
7174
'src/ng/directive/script.js',
7275
'src/ng/directive/select.js',
73-
'src/ng/directive/style.js'
76+
'src/ng/directive/style.js',
77+
'src/ng/directive/validators.js'
7478
],
7579

7680
'angularLoader': [

src/ng/directive/input.js

+7-1,619
Large diffs are not rendered by default.

src/ng/directive/ngChange.js

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
'use strict';
2+
3+
/**
4+
* @ngdoc directive
5+
* @name ngChange
6+
*
7+
* @description
8+
* Evaluate the given expression when the user changes the input.
9+
* The expression is evaluated immediately, unlike the JavaScript onchange event
10+
* which only triggers at the end of a change (usually, when the user leaves the
11+
* form element or presses the return key).
12+
*
13+
* The `ngChange` expression is only evaluated when a change in the input value causes
14+
* a new value to be committed to the model.
15+
*
16+
* It will not be evaluated:
17+
* * if the value returned from the `$parsers` transformation pipeline has not changed
18+
* * if the input has continued to be invalid since the model will stay `null`
19+
* * if the model is changed programmatically and not by a change to the input value
20+
*
21+
*
22+
* Note, this directive requires `ngModel` to be present.
23+
*
24+
* @element input
25+
* @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
26+
* in input value.
27+
*
28+
* @example
29+
* <example name="ngChange-directive" module="changeExample">
30+
* <file name="index.html">
31+
* <script>
32+
* angular.module('changeExample', [])
33+
* .controller('ExampleController', ['$scope', function($scope) {
34+
* $scope.counter = 0;
35+
* $scope.change = function() {
36+
* $scope.counter++;
37+
* };
38+
* }]);
39+
* </script>
40+
* <div ng-controller="ExampleController">
41+
* <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
42+
* <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
43+
* <label for="ng-change-example2">Confirmed</label><br />
44+
* <tt>debug = {{confirmed}}</tt><br/>
45+
* <tt>counter = {{counter}}</tt><br/>
46+
* </div>
47+
* </file>
48+
* <file name="protractor.js" type="protractor">
49+
* var counter = element(by.binding('counter'));
50+
* var debug = element(by.binding('confirmed'));
51+
*
52+
* it('should evaluate the expression if changing from view', function() {
53+
* expect(counter.getText()).toContain('0');
54+
*
55+
* element(by.id('ng-change-example1')).click();
56+
*
57+
* expect(counter.getText()).toContain('1');
58+
* expect(debug.getText()).toContain('true');
59+
* });
60+
*
61+
* it('should not evaluate the expression if changing from model', function() {
62+
* element(by.id('ng-change-example2')).click();
63+
64+
* expect(counter.getText()).toContain('0');
65+
* expect(debug.getText()).toContain('true');
66+
* });
67+
* </file>
68+
* </example>
69+
*/
70+
var ngChangeDirective = valueFn({
71+
restrict: 'A',
72+
require: 'ngModel',
73+
link: function(scope, element, attr, ctrl) {
74+
ctrl.$viewChangeListeners.push(function() {
75+
scope.$eval(attr.ngChange);
76+
});
77+
}
78+
});

src/ng/directive/ngList.js

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
'use strict';
2+
3+
4+
/**
5+
* @ngdoc directive
6+
* @name ngList
7+
*
8+
* @description
9+
* Text input that converts between a delimited string and an array of strings. The default
10+
* delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
11+
* delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
12+
*
13+
* The behaviour of the directive is affected by the use of the `ngTrim` attribute.
14+
* * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
15+
* list item is respected. This implies that the user of the directive is responsible for
16+
* dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
17+
* tab or newline character.
18+
* * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
19+
* when joining the list items back together) and whitespace around each list item is stripped
20+
* before it is added to the model.
21+
*
22+
* ### Example with Validation
23+
*
24+
* <example name="ngList-directive" module="listExample">
25+
* <file name="app.js">
26+
* angular.module('listExample', [])
27+
* .controller('ExampleController', ['$scope', function($scope) {
28+
* $scope.names = ['morpheus', 'neo', 'trinity'];
29+
* }]);
30+
* </file>
31+
* <file name="index.html">
32+
* <form name="myForm" ng-controller="ExampleController">
33+
* List: <input name="namesInput" ng-model="names" ng-list required>
34+
* <span class="error" ng-show="myForm.namesInput.$error.required">
35+
* Required!</span>
36+
* <br>
37+
* <tt>names = {{names}}</tt><br/>
38+
* <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
39+
* <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
40+
* <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
41+
* <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
42+
* </form>
43+
* </file>
44+
* <file name="protractor.js" type="protractor">
45+
* var listInput = element(by.model('names'));
46+
* var names = element(by.exactBinding('names'));
47+
* var valid = element(by.binding('myForm.namesInput.$valid'));
48+
* var error = element(by.css('span.error'));
49+
*
50+
* it('should initialize to model', function() {
51+
* expect(names.getText()).toContain('["morpheus","neo","trinity"]');
52+
* expect(valid.getText()).toContain('true');
53+
* expect(error.getCssValue('display')).toBe('none');
54+
* });
55+
*
56+
* it('should be invalid if empty', function() {
57+
* listInput.clear();
58+
* listInput.sendKeys('');
59+
*
60+
* expect(names.getText()).toContain('');
61+
* expect(valid.getText()).toContain('false');
62+
* expect(error.getCssValue('display')).not.toBe('none');
63+
* });
64+
* </file>
65+
* </example>
66+
*
67+
* ### Example - splitting on whitespace
68+
* <example name="ngList-directive-newlines">
69+
* <file name="index.html">
70+
* <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
71+
* <pre>{{ list | json }}</pre>
72+
* </file>
73+
* <file name="protractor.js" type="protractor">
74+
* it("should split the text by newlines", function() {
75+
* var listInput = element(by.model('list'));
76+
* var output = element(by.binding('list | json'));
77+
* listInput.sendKeys('abc\ndef\nghi');
78+
* expect(output.getText()).toContain('[\n "abc",\n "def",\n "ghi"\n]');
79+
* });
80+
* </file>
81+
* </example>
82+
*
83+
* @element input
84+
* @param {string=} ngList optional delimiter that should be used to split the value.
85+
*/
86+
var ngListDirective = function() {
87+
return {
88+
restrict: 'A',
89+
priority: 100,
90+
require: 'ngModel',
91+
link: function(scope, element, attr, ctrl) {
92+
// We want to control whitespace trimming so we use this convoluted approach
93+
// to access the ngList attribute, which doesn't pre-trim the attribute
94+
var ngList = element.attr(attr.$attr.ngList) || ', ';
95+
var trimValues = attr.ngTrim !== 'false';
96+
var separator = trimValues ? trim(ngList) : ngList;
97+
98+
var parse = function(viewValue) {
99+
// If the viewValue is invalid (say required but empty) it will be `undefined`
100+
if (isUndefined(viewValue)) return;
101+
102+
var list = [];
103+
104+
if (viewValue) {
105+
forEach(viewValue.split(separator), function(value) {
106+
if (value) list.push(trimValues ? trim(value) : value);
107+
});
108+
}
109+
110+
return list;
111+
};
112+
113+
ctrl.$parsers.push(parse);
114+
ctrl.$formatters.push(function(value) {
115+
if (isArray(value)) {
116+
return value.join(ngList);
117+
}
118+
119+
return undefined;
120+
});
121+
122+
// Override the standard $isEmpty because an empty array means the input is empty.
123+
ctrl.$isEmpty = function(value) {
124+
return !value || !value.length;
125+
};
126+
}
127+
};
128+
};

0 commit comments

Comments
 (0)