OLD | NEW |
1 library ng_model_spec; | 1 library ng_model_spec; |
2 | 2 |
3 import '../_specs.dart'; | 3 import '../_specs.dart'; |
4 import 'dart:html' as dom; | 4 import 'dart:html' as dom; |
5 | 5 |
| 6 //----------------------------------------------------------------------------- |
| 7 // Utility functions |
| 8 |
| 9 /* This function simulates typing the given text into the input field. The |
| 10 * text will be added wherever the insertion point happens to be. This method |
| 11 * has as side-effect to set the focus on the input (without setting the |
| 12 * focus, the text dispatch may not work). |
| 13 */ |
| 14 void simulateTypingText(InputElement input, String text) { |
| 15 input..focus()..dispatchEvent(new TextEvent('textInput', data: text)); |
| 16 } |
| 17 |
| 18 bool simulateTypingTextWithConfirmation(InputElement input, String text, |
| 19 { bool shouldWorkForChrome : true }) { |
| 20 bool result; |
| 21 String val = input.value; |
| 22 try { |
| 23 simulateTypingText(input, text); |
| 24 result = input.value == val + text; |
| 25 } catch (e) { |
| 26 result = false; |
| 27 } |
| 28 if (!result && shouldWorkForChrome) expect(isBrowser('Chrome')).toBeFalsy(); |
| 29 return result; |
| 30 } |
| 31 |
| 32 bool isBrowser(String pattern) => dom.window.navigator.userAgent.indexOf(pattern
) > 0; |
| 33 |
| 34 //----------------------------------------------------------------------------- |
| 35 |
6 void main() { | 36 void main() { |
7 describe('ng-model', () { | 37 describe('ng-model', () { |
8 TestBed _; | 38 TestBed _; |
9 | 39 |
10 beforeEach(module((Module module) { | 40 beforeEachModule((Module module) { |
11 module..type(ControllerWithNoLove); | 41 module |
12 })); | 42 ..type(ControllerWithNoLove) |
| 43 ..type(MyCustomInputValidator) |
| 44 ..type(CountingValidator); |
| 45 }); |
13 | 46 |
14 beforeEach(inject((TestBed tb) => _ = tb)); | 47 beforeEach((TestBed tb) => _ = tb); |
15 | 48 |
16 describe('type="text" like', () { | 49 describe('type="text" like', () { |
17 it('should update input value from model', inject(() { | 50 it('should update input value from model', () { |
18 _.compile('<input type="text" ng-model="model">'); | 51 _.compile('<input type="text" ng-model="model">'); |
19 _.rootScope.apply(); | 52 _.rootScope.apply(); |
20 | 53 |
21 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 54 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
22 | 55 |
23 _.rootScope.apply('model = "misko"'); | 56 _.rootScope.apply('model = "misko"'); |
24 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 57 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
25 })); | 58 }); |
26 | 59 |
27 it('should render null as the empty string', inject(() { | 60 it('should render null as the empty string', () { |
28 _.compile('<input type="text" ng-model="model">'); | 61 _.compile('<input type="text" ng-model="model">'); |
29 _.rootScope.apply(); | 62 _.rootScope.apply(); |
30 | 63 |
31 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 64 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
32 | 65 |
33 _.rootScope.apply('model = null'); | 66 _.rootScope.apply('model = null'); |
34 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 67 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
35 })); | 68 }); |
36 | 69 |
37 it('should update model from the input value', inject(() { | 70 it('should update model from the input value', () { |
38 _.compile('<input type="text" ng-model="model" probe="p">'); | 71 _.compile('<input type="text" ng-model="model" probe="p">'); |
39 Probe probe = _.rootScope.context['p']; | 72 Probe probe = _.rootScope.context['p']; |
40 var ngModel = probe.directive(NgModel); | 73 var ngModel = probe.directive(NgModel); |
41 InputElement inputElement = probe.element; | 74 InputElement inputElement = probe.element; |
42 | 75 |
43 inputElement.value = 'abc'; | 76 inputElement.value = 'abc'; |
44 _.triggerEvent(inputElement, 'change'); | 77 _.triggerEvent(inputElement, 'change'); |
45 expect(_.rootScope.context['model']).toEqual('abc'); | 78 expect(_.rootScope.context['model']).toEqual('abc'); |
46 | 79 |
47 inputElement.value = 'def'; | 80 inputElement.value = 'def'; |
48 var input = probe.directive(InputTextLikeDirective); | 81 var input = probe.directive(InputTextLike); |
49 input.processValue(); | 82 input.processValue(); |
50 expect(_.rootScope.context['model']).toEqual('def'); | 83 expect(_.rootScope.context['model']).toEqual('def'); |
51 })); | 84 }); |
52 | 85 |
53 it('should update model from the input value for type=number', inject(() { | 86 it('should write to input only if the value is different', |
| 87 (Injector i, Animate animate) { |
| 88 |
| 89 var scope = _.rootScope; |
| 90 var element = new dom.InputElement(); |
| 91 var ngElement = new NgElement(element, scope, animate); |
| 92 |
| 93 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
| 94 nodeAttrs['ng-model'] = 'model'; |
| 95 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), |
| 96 nodeAttrs, new Animate()); |
| 97 dom.querySelector('body').append(element); |
| 98 var input = new InputTextLike(element, model, scope); |
| 99 |
| 100 element |
| 101 ..value = 'abc' |
| 102 ..selectionStart = 1 |
| 103 ..selectionEnd = 2; |
| 104 |
| 105 scope.apply(() { |
| 106 scope.context['model'] = 'abc'; |
| 107 }); |
| 108 |
| 109 expect(element.value).toEqual('abc'); |
| 110 // No update. selectionStart/End is unchanged. |
| 111 expect(element.selectionStart).toEqual(1); |
| 112 expect(element.selectionEnd).toEqual(2); |
| 113 |
| 114 scope.apply(() { |
| 115 scope.context['model'] = 'xyz'; |
| 116 }); |
| 117 |
| 118 // Value updated. selectionStart/End changed. |
| 119 expect(element.value).toEqual('xyz'); |
| 120 expect(element.selectionStart).toEqual(3); |
| 121 expect(element.selectionEnd).toEqual(3); |
| 122 }); |
| 123 |
| 124 it('should only render the input value upon the next digest', (Scope scope
) { |
| 125 _.compile('<input type="text" ng-model="model" probe="p">'); |
| 126 Probe probe = _.rootScope.context['p']; |
| 127 var ngModel = probe.directive(NgModel); |
| 128 InputElement inputElement = probe.element; |
| 129 |
| 130 ngModel.render('xyz'); |
| 131 scope.context['model'] = 'xyz'; |
| 132 |
| 133 expect(inputElement.value).not.toEqual('xyz'); |
| 134 |
| 135 scope.apply(); |
| 136 |
| 137 expect(inputElement.value).toEqual('xyz'); |
| 138 }); |
| 139 }); |
| 140 |
| 141 describe('type="number" or type="range"', () { |
| 142 |
| 143 it('should update model from the input value for type=number', () { |
54 _.compile('<input type="number" ng-model="model" probe="p">'); | 144 _.compile('<input type="number" ng-model="model" probe="p">'); |
55 Probe probe = _.rootScope.context['p']; | 145 Probe probe = _.rootScope.context['p']; |
56 var ngModel = probe.directive(NgModel); | 146 var ngModel = probe.directive(NgModel); |
57 InputElement inputElement = probe.element; | 147 InputElement inputElement = probe.element; |
58 | 148 |
59 inputElement.value = '12'; | 149 inputElement.value = '12'; |
60 _.triggerEvent(inputElement, 'change'); | 150 _.triggerEvent(inputElement, 'change'); |
61 expect(_.rootScope.context['model']).toEqual(12); | 151 expect(_.rootScope.context['model']).toEqual(12); |
62 | 152 |
63 inputElement.value = '14'; | 153 inputElement.value = '14'; |
64 var input = probe.directive(InputNumberLikeDirective); | 154 var input = probe.directive(InputNumberLike); |
65 input.processValue(); | 155 input.processValue(); |
66 expect(_.rootScope.context['model']).toEqual(14); | 156 expect(_.rootScope.context['model']).toEqual(14); |
67 })); | 157 }); |
68 | 158 |
69 it('should update input type=number to blank when model is null', inject((
) { | 159 it('should update input type=number to blank when model is null', () { |
70 _.compile('<input type="number" ng-model="model" probe="p">'); | 160 _.compile('<input type="number" ng-model="model" probe="p">'); |
71 Probe probe = _.rootScope.context['p']; | 161 Probe probe = _.rootScope.context['p']; |
72 var ngModel = probe.directive(NgModel); | 162 var ngModel = probe.directive(NgModel); |
73 InputElement inputElement = probe.element; | 163 InputElement inputElement = probe.element; |
74 | 164 |
75 inputElement.value = '12'; | 165 inputElement.value = '12'; |
76 _.triggerEvent(inputElement, 'change'); | 166 _.triggerEvent(inputElement, 'change'); |
77 expect(_.rootScope.context['model']).toEqual(12); | 167 expect(_.rootScope.context['model']).toEqual(12); |
78 | 168 |
79 _.rootScope.context['model'] = null; | 169 _.rootScope.context['model'] = null; |
80 _.rootScope.apply(); | 170 _.rootScope.apply(); |
81 expect(inputElement.value).toEqual(''); | 171 expect(inputElement.value).toEqual(''); |
82 })); | 172 }); |
83 | 173 |
84 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { | 174 it('should be invalid when the input value results in a NaN value', () { |
85 var scope = _.rootScope; | 175 _.compile('<input type="number" ng-model="model" probe="p">'); |
86 var element = new dom.InputElement(); | 176 Probe probe = _.rootScope.context['p']; |
87 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 177 var ngModel = probe.directive(NgModel); |
88 nodeAttrs['ng-model'] = 'model'; | 178 InputElement inputElement = probe.element; |
89 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | |
90 dom.querySelector('body').append(element); | |
91 var input = new InputTextLikeDirective(element, model, scope); | |
92 | 179 |
93 element | 180 inputElement.value = 'aa'; |
94 ..value = 'abc' | 181 _.triggerEvent(inputElement, 'change'); |
95 ..selectionStart = 1 | 182 expect(_.rootScope.context['model'].isNaN).toBe(true); |
96 ..selectionEnd = 2; | 183 expect(ngModel.valid).toBe(false); |
| 184 }); |
97 | 185 |
98 model.render('abc'); | 186 it('should leave input unchanged when text does not represent a valid numb
er', (Injector i) { |
99 | |
100 expect(element.value).toEqual('abc'); | |
101 // No update. selectionStart/End is unchanged. | |
102 expect(element.selectionStart).toEqual(1); | |
103 expect(element.selectionEnd).toEqual(2); | |
104 | |
105 model.render('xyz'); | |
106 | |
107 // Value updated. selectionStart/End changed. | |
108 expect(element.value).toEqual('xyz'); | |
109 expect(element.selectionStart).toEqual(3); | |
110 expect(element.selectionEnd).toEqual(3); | |
111 })); | |
112 }); | |
113 | |
114 /* This function simulates typing the given text into the input | |
115 * field. The text will be added wherever the insertion point | |
116 * happens to be. This method has as side-effect to set the | |
117 * focus on the input (without setting the focus the text | |
118 * dispatch may not work). | |
119 */ | |
120 void simulateTypingText(InputElement input, String text) { | |
121 input..focus()..dispatchEvent(new TextEvent('textInput', data: text)); | |
122 } | |
123 | |
124 describe('type="number" like', () { | |
125 | |
126 it('should leave input unchanged when text does not represent a valid numb
er', inject((Injector i) { | |
127 var modelFieldName = 'modelForNumFromInvalid1'; | 187 var modelFieldName = 'modelForNumFromInvalid1'; |
128 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); | 188 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); |
129 dom.querySelector('body').append(element); | 189 dom.querySelector('body').append(element); |
130 | 190 |
| 191 if (!simulateTypingTextWithConfirmation(element, '1')) return; // skip t
est. |
| 192 element.value = ''; // reset input |
| 193 |
131 // This test will progressively enter the text '1e1' | 194 // This test will progressively enter the text '1e1' |
132 // '1' is a valid number. | 195 // '1' is a valid number. |
133 // '1e' is not a valid number. | 196 // '1e' is not a valid number. |
134 // '1e1' is again a valid number (with an exponent) | 197 // '1e1' is again a valid number (with an exponent) |
135 | 198 |
136 simulateTypingText(element, '1'); | 199 simulateTypingText(element, '1'); |
137 _.triggerEvent(element, 'change'); | 200 _.triggerEvent(element, 'change'); |
138 expect(element.value).toEqual('1'); | 201 expect(element.value).toEqual('1'); |
139 expect(_.rootScope.context[modelFieldName]).toEqual(1); | 202 expect(_.rootScope.context[modelFieldName]).toEqual(1); |
140 | 203 |
141 simulateTypingText(element, 'e'); | 204 simulateTypingText(element, 'e'); |
142 // Because the text is not a valid number, the element value is empty. | 205 // Because the text is not a valid number, the element value is empty. |
143 expect(element.value).toEqual(''); | 206 expect(element.value).toEqual(''); |
144 // When the input is invalid, the model is [double.NAN]: | 207 // When the input is invalid, the model is [double.NAN]: |
145 _.triggerEvent(element, 'change'); | 208 _.triggerEvent(element, 'change'); |
146 expect(_.rootScope.context[modelFieldName].isNaN).toBeTruthy(); | 209 expect(_.rootScope.context[modelFieldName].isNaN).toBeTruthy(); |
147 | 210 |
148 simulateTypingText(element, '1'); | 211 simulateTypingText(element, '1'); |
149 _.triggerEvent(element, 'change'); | 212 _.triggerEvent(element, 'change'); |
150 expect(element.value).toEqual('1e1'); | 213 expect(element.value).toEqual('1e1'); |
151 expect(_.rootScope.context[modelFieldName]).toEqual(10); | 214 expect(_.rootScope.context[modelFieldName]).toEqual(10); |
152 })); | 215 }); |
153 | 216 |
154 it('should not reformat user input to equivalent numeric representation',
inject((Injector i) { | 217 it('should not reformat user input to equivalent numeric representation',
(Injector i) { |
155 var modelFieldName = 'modelForNumFromInvalid2'; | 218 var modelFieldName = 'modelForNumFromInvalid2'; |
156 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); | 219 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); |
157 dom.querySelector('body').append(element); | 220 dom.querySelector('body').append(element); |
158 | 221 |
| 222 if (!simulateTypingTextWithConfirmation(element, '1')) return; // skip t
est. |
| 223 element.value = ''; // reset input |
| 224 |
159 simulateTypingText(element, '1e-1'); | 225 simulateTypingText(element, '1e-1'); |
160 expect(element.value).toEqual('1e-1'); | 226 expect(element.value).toEqual('1e-1'); |
161 expect(_.rootScope.context[modelFieldName]).toEqual(0.1); | 227 expect(_.rootScope.context[modelFieldName]).toEqual(0.1); |
162 })); | 228 }); |
163 | 229 |
164 it('should update input value from model', inject(() { | 230 it('should update input value from model', () { |
165 _.compile('<input type="number" ng-model="model">'); | 231 _.compile('<input type="number" ng-model="model">'); |
166 _.rootScope.apply(); | 232 _.rootScope.apply(); |
167 | 233 |
168 _.rootScope.apply('model = 42'); | 234 _.rootScope.apply('model = 42'); |
169 expect((_.rootElement as dom.InputElement).value).toEqual('42'); | 235 expect((_.rootElement as dom.InputElement).value).toEqual('42'); |
170 })); | 236 }); |
171 | 237 |
172 it('should update input value from model for range inputs', inject(() { | 238 it('should update input value from model for range inputs', () { |
173 _.compile('<input type="range" ng-model="model">'); | 239 _.compile('<input type="range" ng-model="model">'); |
174 _.rootScope.apply(); | 240 _.rootScope.apply(); |
175 | 241 |
176 _.rootScope.apply('model = 42'); | 242 _.rootScope.apply('model = 42'); |
177 expect((_.rootElement as dom.InputElement).value).toEqual('42'); | 243 expect((_.rootElement as dom.InputElement).value).toEqual('42'); |
178 })); | 244 }); |
179 | 245 |
180 it('should update model from the input value', inject(() { | 246 it('should update model from the input value', () { |
181 _.compile('<input type="number" ng-model="model" probe="p">'); | 247 _.compile('<input type="number" ng-model="model" probe="p">'); |
182 Probe probe = _.rootScope.context['p']; | 248 Probe probe = _.rootScope.context['p']; |
183 var ngModel = probe.directive(NgModel); | 249 var ngModel = probe.directive(NgModel); |
184 InputElement inputElement = probe.element; | 250 InputElement inputElement = probe.element; |
185 | 251 |
186 inputElement.value = '42'; | 252 inputElement.value = '42'; |
187 _.triggerEvent(inputElement, 'change'); | 253 _.triggerEvent(inputElement, 'change'); |
188 expect(_.rootScope.context['model']).toEqual(42); | 254 expect(_.rootScope.context['model']).toEqual(42); |
189 | 255 |
190 inputElement.value = '43'; | 256 inputElement.value = '43'; |
191 var input = probe.directive(InputNumberLikeDirective); | 257 var input = probe.directive(InputNumberLike); |
192 input.processValue(); | 258 input.processValue(); |
193 expect(_.rootScope.context['model']).toEqual(43); | 259 expect(_.rootScope.context['model']).toEqual(43); |
194 })); | 260 }); |
195 | 261 |
196 it('should update model to NaN from a blank input value', inject(() { | 262 it('should update model to NaN from a blank input value', () { |
197 _.compile('<input type="number" ng-model="model" probe="p">'); | 263 _.compile('<input type="number" ng-model="model" probe="p">'); |
198 Probe probe = _.rootScope.context['p']; | 264 Probe probe = _.rootScope.context['p']; |
199 var ngModel = probe.directive(NgModel); | 265 var ngModel = probe.directive(NgModel); |
200 InputElement inputElement = probe.element; | 266 InputElement inputElement = probe.element; |
201 | 267 |
202 inputElement.value = ''; | 268 inputElement.value = ''; |
203 _.triggerEvent(inputElement, 'change'); | 269 _.triggerEvent(inputElement, 'change'); |
204 expect(_.rootScope.context['model'].isNaN).toBeTruthy(); | 270 expect(_.rootScope.context['model'].isNaN).toBeTruthy(); |
205 })); | 271 }); |
206 | 272 |
207 it('should update model from the input value for range inputs', inject(()
{ | 273 it('should update model from the input value for range inputs', () { |
208 _.compile('<input type="range" ng-model="model" probe="p">'); | 274 _.compile('<input type="range" ng-model="model" probe="p">'); |
209 Probe probe = _.rootScope.context['p']; | 275 Probe probe = _.rootScope.context['p']; |
210 var ngModel = probe.directive(NgModel); | 276 var ngModel = probe.directive(NgModel); |
211 InputElement inputElement = probe.element; | 277 InputElement inputElement = probe.element; |
212 | 278 |
213 inputElement.value = '42'; | 279 inputElement.value = '42'; |
214 _.triggerEvent(inputElement, 'change'); | 280 _.triggerEvent(inputElement, 'change'); |
215 expect(_.rootScope.context['model']).toEqual(42); | 281 expect(_.rootScope.context['model']).toEqual(42); |
216 | 282 |
217 inputElement.value = '43'; | 283 inputElement.value = '43'; |
218 var input = probe.directive(InputNumberLikeDirective); | 284 var input = probe.directive(InputNumberLike); |
219 input.processValue(); | 285 input.processValue(); |
220 expect(_.rootScope.context['model']).toEqual(43); | 286 expect(_.rootScope.context['model']).toEqual(43); |
221 })); | 287 }); |
222 | 288 |
223 it('should update model to a native default value from a blank range input
value', inject(() { | 289 it('should update model to a native default value from a blank range input
value', () { |
224 _.compile('<input type="range" ng-model="model" probe="p">'); | 290 _.compile('<input type="range" ng-model="model" probe="p">'); |
225 Probe probe = _.rootScope.context['p']; | 291 Probe probe = _.rootScope.context['p']; |
226 var ngModel = probe.directive(NgModel); | 292 var ngModel = probe.directive(NgModel); |
227 InputElement inputElement = probe.element; | 293 InputElement inputElement = probe.element; |
228 | 294 |
229 inputElement.value = ''; | 295 inputElement.value = ''; |
230 _.triggerEvent(inputElement, 'change'); | 296 _.triggerEvent(inputElement, 'change'); |
231 expect(_.rootScope.context['model']).toBeDefined(); | 297 expect(_.rootScope.context['model']).toBeDefined(); |
232 })); | 298 }); |
233 | 299 |
234 it('should render null as blank', inject(() { | 300 it('should render null as blank', () { |
235 _.compile('<input type="number" ng-model="model">'); | 301 _.compile('<input type="number" ng-model="model">'); |
236 _.rootScope.apply(); | 302 _.rootScope.apply(); |
237 | 303 |
238 _.rootScope.apply('model = null'); | 304 _.rootScope.apply('model = null'); |
239 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 305 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
240 })); | 306 }); |
| 307 |
| 308 it('should only render the input value upon the next digest', (Scope scope
) { |
| 309 _.compile('<input type="number" ng-model="model" probe="p">'); |
| 310 Probe probe = _.rootScope.context['p']; |
| 311 var ngModel = probe.directive(NgModel); |
| 312 InputElement inputElement = probe.element; |
| 313 |
| 314 ngModel.render(123); |
| 315 scope.context['model'] = 123; |
| 316 |
| 317 expect(inputElement.value).not.toEqual('123'); |
| 318 |
| 319 scope.apply(); |
| 320 |
| 321 expect(inputElement.value).toEqual('123'); |
| 322 }); |
241 | 323 |
242 }); | 324 }); |
243 | 325 |
244 describe('type="password"', () { | 326 describe('type="password"', () { |
245 it('should update input value from model', inject(() { | 327 it('should update input value from model', () { |
246 _.compile('<input type="password" ng-model="model">'); | 328 _.compile('<input type="password" ng-model="model">'); |
247 _.rootScope.apply(); | 329 _.rootScope.apply(); |
248 | 330 |
249 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 331 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
250 | 332 |
251 _.rootScope.apply('model = "misko"'); | 333 _.rootScope.apply('model = "misko"'); |
252 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 334 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
253 })); | 335 }); |
254 | 336 |
255 it('should render null as the empty string', inject(() { | 337 it('should render null as the empty string', () { |
256 _.compile('<input type="password" ng-model="model">'); | 338 _.compile('<input type="password" ng-model="model">'); |
257 _.rootScope.apply(); | 339 _.rootScope.apply(); |
258 | 340 |
259 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 341 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
260 | 342 |
261 _.rootScope.apply('model = null'); | 343 _.rootScope.apply('model = null'); |
262 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 344 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
263 })); | 345 }); |
264 | 346 |
265 it('should update model from the input value', inject(() { | 347 it('should update model from the input value', () { |
266 _.compile('<input type="password" ng-model="model" probe="p">'); | 348 _.compile('<input type="password" ng-model="model" probe="p">'); |
267 Probe probe = _.rootScope.context['p']; | 349 Probe probe = _.rootScope.context['p']; |
268 var ngModel = probe.directive(NgModel); | 350 var ngModel = probe.directive(NgModel); |
269 InputElement inputElement = probe.element; | 351 InputElement inputElement = probe.element; |
270 | 352 |
271 inputElement.value = 'abc'; | 353 inputElement.value = 'abc'; |
272 _.triggerEvent(inputElement, 'change'); | 354 _.triggerEvent(inputElement, 'change'); |
273 expect(_.rootScope.context['model']).toEqual('abc'); | 355 expect(_.rootScope.context['model']).toEqual('abc'); |
274 | 356 |
275 inputElement.value = 'def'; | 357 inputElement.value = 'def'; |
276 var input = probe.directive(InputTextLikeDirective); | 358 var input = probe.directive(InputTextLike); |
277 input.processValue(); | 359 input.processValue(); |
278 expect(_.rootScope.context['model']).toEqual('def'); | 360 expect(_.rootScope.context['model']).toEqual('def'); |
279 | 361 |
280 })); | 362 }); |
281 | 363 |
282 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { | 364 it('should write to input only if value is different', |
| 365 (Injector i, Animate animate) { |
| 366 |
283 var scope = _.rootScope; | 367 var scope = _.rootScope; |
284 var element = new dom.InputElement(); | 368 var element = new dom.InputElement(); |
| 369 var ngElement = new NgElement(element, scope, animate); |
| 370 |
285 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 371 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
286 nodeAttrs['ng-model'] = 'model'; | 372 nodeAttrs['ng-model'] = 'model'; |
287 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | 373 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), |
| 374 nodeAttrs, new Animate()); |
288 dom.querySelector('body').append(element); | 375 dom.querySelector('body').append(element); |
289 var input = new InputTextLikeDirective(element, model, scope); | 376 var input = new InputTextLike(element, model, scope); |
290 | 377 |
291 element | 378 element |
292 ..value = 'abc' | 379 ..value = 'abc' |
293 ..selectionStart = 1 | 380 ..selectionStart = 1 |
294 ..selectionEnd = 2; | 381 ..selectionEnd = 2; |
295 | 382 |
296 model.render('abc'); | 383 scope.apply(() { |
| 384 scope.context['model'] = 'abc'; |
| 385 }); |
297 | 386 |
298 expect(element.value).toEqual('abc'); | 387 expect(element.value).toEqual('abc'); |
299 expect(element.selectionStart).toEqual(1); | 388 expect(element.selectionStart).toEqual(1); |
300 expect(element.selectionEnd).toEqual(2); | 389 expect(element.selectionEnd).toEqual(2); |
301 | 390 |
302 model.render('xyz'); | 391 scope.apply(() { |
| 392 scope.context['model'] = 'xyz'; |
| 393 }); |
303 | 394 |
304 expect(element.value).toEqual('xyz'); | 395 expect(element.value).toEqual('xyz'); |
305 expect(element.selectionStart).toEqual(3); | 396 expect(element.selectionStart).toEqual(3); |
306 expect(element.selectionEnd).toEqual(3); | 397 expect(element.selectionEnd).toEqual(3); |
307 })); | 398 }); |
| 399 |
| 400 it('should only render the input value upon the next digest', (Scope scope
) { |
| 401 _.compile('<input type="password" ng-model="model" probe="p">'); |
| 402 Probe probe = _.rootScope.context['p']; |
| 403 var ngModel = probe.directive(NgModel); |
| 404 InputElement inputElement = probe.element; |
| 405 |
| 406 ngModel.render('xyz'); |
| 407 scope.context['model'] = 'xyz'; |
| 408 |
| 409 expect(inputElement.value).not.toEqual('xyz'); |
| 410 |
| 411 scope.apply(); |
| 412 |
| 413 expect(inputElement.value).toEqual('xyz'); |
| 414 }); |
308 }); | 415 }); |
309 | 416 |
310 describe('type="search"', () { | 417 describe('type="search"', () { |
311 it('should update input value from model', inject(() { | 418 it('should update input value from model', () { |
312 _.compile('<input type="search" ng-model="model">'); | 419 _.compile('<input type="search" ng-model="model">'); |
313 _.rootScope.apply(); | 420 _.rootScope.apply(); |
314 | 421 |
315 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 422 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
316 | 423 |
317 _.rootScope.apply('model = "misko"'); | 424 _.rootScope.apply('model = "misko"'); |
318 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 425 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
319 })); | 426 }); |
320 | 427 |
321 it('should render null as the empty string', inject(() { | 428 it('should render null as the empty string', () { |
322 _.compile('<input type="search" ng-model="model">'); | 429 _.compile('<input type="search" ng-model="model">'); |
323 _.rootScope.apply(); | 430 _.rootScope.apply(); |
324 | 431 |
325 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 432 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
326 | 433 |
327 _.rootScope.apply('model = null'); | 434 _.rootScope.apply('model = null'); |
328 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 435 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
329 })); | 436 }); |
330 | 437 |
331 it('should update model from the input value', inject(() { | 438 it('should update model from the input value', () { |
332 _.compile('<input type="search" ng-model="model" probe="p">'); | 439 _.compile('<input type="search" ng-model="model" probe="p">'); |
333 Probe probe = _.rootScope.context['p']; | 440 Probe probe = _.rootScope.context['p']; |
334 var ngModel = probe.directive(NgModel); | 441 var ngModel = probe.directive(NgModel); |
335 InputElement inputElement = probe.element; | 442 InputElement inputElement = probe.element; |
336 | 443 |
337 inputElement.value = 'abc'; | 444 inputElement.value = 'abc'; |
338 _.triggerEvent(inputElement, 'change'); | 445 _.triggerEvent(inputElement, 'change'); |
339 expect(_.rootScope.context['model']).toEqual('abc'); | 446 expect(_.rootScope.context['model']).toEqual('abc'); |
340 | 447 |
341 inputElement.value = 'def'; | 448 inputElement.value = 'def'; |
342 var input = probe.directive(InputTextLikeDirective); | 449 var input = probe.directive(InputTextLike); |
343 input.processValue(); | 450 input.processValue(); |
344 expect(_.rootScope.context['model']).toEqual('def'); | 451 expect(_.rootScope.context['model']).toEqual('def'); |
345 })); | 452 }); |
346 | 453 |
347 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { | 454 it('should write to input only if value is different', |
| 455 (Injector i, Animate animate) { |
| 456 |
348 var scope = _.rootScope; | 457 var scope = _.rootScope; |
349 var element = new dom.InputElement(); | 458 var element = new dom.InputElement(); |
| 459 var ngElement = new NgElement(element, scope, animate); |
| 460 |
350 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 461 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
351 nodeAttrs['ng-model'] = 'model'; | 462 nodeAttrs['ng-model'] = 'model'; |
352 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | 463 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), |
| 464 nodeAttrs, new Animate()); |
353 dom.querySelector('body').append(element); | 465 dom.querySelector('body').append(element); |
354 var input = new InputTextLikeDirective(element, model, scope); | 466 var input = new InputTextLike(element, model, scope); |
355 | 467 |
356 element | 468 element |
357 ..value = 'abc' | 469 ..value = 'abc' |
358 ..selectionStart = 1 | 470 ..selectionStart = 1 |
359 ..selectionEnd = 2; | 471 ..selectionEnd = 2; |
360 | 472 |
361 model.render('abc'); | 473 scope.apply(() { |
| 474 scope.context['model'] = 'abc'; |
| 475 }); |
362 | 476 |
363 expect(element.value).toEqual('abc'); | 477 expect(element.value).toEqual('abc'); |
364 // No update. selectionStart/End is unchanged. | 478 // No update. selectionStart/End is unchanged. |
365 expect(element.selectionStart).toEqual(1); | 479 expect(element.selectionStart).toEqual(1); |
366 expect(element.selectionEnd).toEqual(2); | 480 expect(element.selectionEnd).toEqual(2); |
367 | 481 |
368 model.render('xyz'); | 482 scope.apply(() { |
| 483 scope.context['model'] = 'xyz'; |
| 484 }); |
369 | 485 |
370 // Value updated. selectionStart/End changed. | 486 // Value updated. selectionStart/End changed. |
371 expect(element.value).toEqual('xyz'); | 487 expect(element.value).toEqual('xyz'); |
372 expect(element.selectionStart).toEqual(3); | 488 expect(element.selectionStart).toEqual(3); |
373 expect(element.selectionEnd).toEqual(3); | 489 expect(element.selectionEnd).toEqual(3); |
374 })); | 490 }); |
| 491 |
| 492 it('should only render the input value upon the next digest', (Scope scope
) { |
| 493 _.compile('<input type="search" ng-model="model" probe="p">'); |
| 494 Probe probe = _.rootScope.context['p']; |
| 495 var ngModel = probe.directive(NgModel); |
| 496 InputElement inputElement = probe.element; |
| 497 |
| 498 ngModel.render('xyz'); |
| 499 scope.context['model'] = 'xyz'; |
| 500 |
| 501 expect(inputElement.value).not.toEqual('xyz'); |
| 502 |
| 503 scope.apply(); |
| 504 |
| 505 expect(inputElement.value).toEqual('xyz'); |
| 506 }); |
375 }); | 507 }); |
376 | 508 |
377 describe('no type attribute', () { | 509 describe('no type attribute', () { |
378 it('should be set "text" as default value for "type" attribute', inject(()
{ | 510 it('should be set "text" as default value for "type" attribute', () { |
379 _.compile('<input ng-model="model">'); | 511 _.compile('<input ng-model="model">'); |
380 _.rootScope.apply(); | 512 _.rootScope.apply(); |
381 expect((_.rootElement as dom.InputElement).attributes['type']).toEqual('
text'); | 513 expect((_.rootElement as dom.InputElement).attributes['type']).toEqual('
text'); |
382 })); | 514 }); |
383 | 515 |
384 it('should update input value from model', inject(() { | 516 it('should update input value from model', () { |
385 _.compile('<input ng-model="model">'); | 517 _.compile('<input ng-model="model">'); |
386 _.rootScope.apply(); | 518 _.rootScope.apply(); |
387 | 519 |
388 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 520 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
389 | 521 |
390 _.rootScope.apply('model = "misko"'); | 522 _.rootScope.apply('model = "misko"'); |
391 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 523 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
392 })); | 524 }); |
393 | 525 |
394 it('should render null as the empty string', inject(() { | 526 it('should render null as the empty string', () { |
395 _.compile('<input ng-model="model">'); | 527 _.compile('<input ng-model="model">'); |
396 _.rootScope.apply(); | 528 _.rootScope.apply(); |
397 | 529 |
398 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 530 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
399 | 531 |
400 _.rootScope.apply('model = null'); | 532 _.rootScope.apply('model = null'); |
401 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 533 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
402 })); | 534 }); |
403 | 535 |
404 it('should update model from the input value', inject(() { | 536 it('should update model from the input value', () { |
405 _.compile('<input ng-model="model" probe="p">'); | 537 _.compile('<input ng-model="model" probe="p">'); |
406 Probe probe = _.rootScope.context['p']; | 538 Probe probe = _.rootScope.context['p']; |
407 var ngModel = probe.directive(NgModel); | 539 var ngModel = probe.directive(NgModel); |
408 InputElement inputElement = probe.element; | 540 InputElement inputElement = probe.element; |
409 | 541 |
410 inputElement.value = 'abc'; | 542 inputElement.value = 'abc'; |
411 _.triggerEvent(inputElement, 'change'); | 543 _.triggerEvent(inputElement, 'change'); |
412 expect(_.rootScope.context['model']).toEqual('abc'); | 544 expect(_.rootScope.context['model']).toEqual('abc'); |
413 | 545 |
414 inputElement.value = 'def'; | 546 inputElement.value = 'def'; |
415 var input = probe.directive(InputTextLikeDirective); | 547 var input = probe.directive(InputTextLike); |
416 input.processValue(); | 548 input.processValue(); |
417 expect(_.rootScope.context['model']).toEqual('def'); | 549 expect(_.rootScope.context['model']).toEqual('def'); |
418 })); | 550 }); |
419 | 551 |
420 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { | 552 it('should write to input only if value is different', |
| 553 (Injector i, Animate animate) { |
| 554 |
421 var scope = _.rootScope; | 555 var scope = _.rootScope; |
422 var element = new dom.InputElement(); | 556 var element = new dom.InputElement(); |
| 557 var ngElement = new NgElement(element, scope, animate); |
| 558 |
423 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 559 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
424 nodeAttrs['ng-model'] = 'model'; | 560 nodeAttrs['ng-model'] = 'model'; |
425 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | 561 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), |
| 562 nodeAttrs, new Animate()); |
426 dom.querySelector('body').append(element); | 563 dom.querySelector('body').append(element); |
427 var input = new InputTextLikeDirective(element, model, scope); | 564 var input = new InputTextLike(element, model, scope); |
428 | 565 |
429 element | 566 element |
430 ..value = 'abc' | 567 ..value = 'abc' |
431 ..selectionStart = 1 | 568 ..selectionStart = 1 |
432 ..selectionEnd = 2; | 569 ..selectionEnd = 2; |
433 | 570 |
434 model.render('abc'); | 571 scope.apply(() { |
| 572 scope.context['model'] = 'abc'; |
| 573 }); |
435 | 574 |
436 expect(element.value).toEqual('abc'); | 575 expect(element.value).toEqual('abc'); |
437 expect(element.selectionStart).toEqual(1); | 576 expect(element.selectionStart).toEqual(1); |
438 expect(element.selectionEnd).toEqual(2); | 577 expect(element.selectionEnd).toEqual(2); |
439 | 578 |
440 model.render('xyz'); | 579 scope.apply(() { |
| 580 scope.context['model'] = 'xyz'; |
| 581 }); |
441 | 582 |
442 expect(element.value).toEqual('xyz'); | 583 expect(element.value).toEqual('xyz'); |
443 expect(element.selectionStart).toEqual(3); | 584 expect(element.selectionStart).toEqual(3); |
444 expect(element.selectionEnd).toEqual(3); | 585 expect(element.selectionEnd).toEqual(3); |
445 })); | 586 }); |
| 587 |
| 588 it('should only render the input value upon the next digest', (Scope scope
) { |
| 589 _.compile('<input ng-model="model" probe="p">'); |
| 590 Probe probe = _.rootScope.context['p']; |
| 591 var ngModel = probe.directive(NgModel); |
| 592 InputElement inputElement = probe.element; |
| 593 |
| 594 ngModel.render('xyz'); |
| 595 scope.context['model'] = 'xyz'; |
| 596 |
| 597 expect(inputElement.value).not.toEqual('xyz'); |
| 598 |
| 599 scope.apply(); |
| 600 |
| 601 expect(inputElement.value).toEqual('xyz'); |
| 602 }); |
446 }); | 603 }); |
447 | 604 |
448 describe('type="checkbox"', () { | 605 describe('type="checkbox"', () { |
449 it('should update input value from model', inject((Scope scope) { | 606 it('should update input value from model', (Scope scope) { |
450 var element = _.compile('<input type="checkbox" ng-model="model">'); | 607 var element = _.compile('<input type="checkbox" ng-model="model">'); |
451 | 608 |
452 scope.apply(() { | 609 scope.apply(() { |
453 scope.context['model'] = true; | 610 scope.context['model'] = true; |
454 }); | 611 }); |
455 expect(element.checked).toBe(true); | 612 expect(element.checked).toBe(true); |
456 | 613 |
457 scope.apply(() { | 614 scope.apply(() { |
458 scope.context['model'] = false; | 615 scope.context['model'] = false; |
459 }); | 616 }); |
460 expect(element.checked).toBe(false); | 617 expect(element.checked).toBe(false); |
461 })); | 618 }); |
462 | 619 |
463 it('should render as dirty when checked', inject((Scope scope) { | 620 it('should render as dirty when checked', (Scope scope) { |
464 var element = _.compile('<input type="text" ng-model="my_model" probe="i
" />'); | 621 var element = _.compile('<input type="text" ng-model="my_model" probe="i
" />'); |
465 Probe probe = _.rootScope.context['i']; | 622 Probe probe = _.rootScope.context['i']; |
466 var model = probe.directive(NgModel); | 623 var model = probe.directive(NgModel); |
467 | 624 |
468 expect(model.pristine).toEqual(true); | 625 expect(model.pristine).toEqual(true); |
469 expect(model.dirty).toEqual(false); | 626 expect(model.dirty).toEqual(false); |
470 | 627 |
471 _.triggerEvent(element, 'change'); | 628 _.triggerEvent(element, 'change'); |
472 | 629 |
473 expect(model.pristine).toEqual(false); | 630 expect(model.pristine).toEqual(false); |
474 expect(model.dirty).toEqual(true); | 631 expect(model.dirty).toEqual(true); |
475 })); | 632 }); |
476 | 633 |
477 | 634 it('should update input value from model using ng-true-value/false', (Scop
e scope) { |
478 it('should update input value from model using ng-true-value/false', injec
t((Scope scope) { | |
479 var element = _.compile('<input type="checkbox" ng-model="model" ng-true
-value="1" ng-false-value="0">'); | 635 var element = _.compile('<input type="checkbox" ng-model="model" ng-true
-value="1" ng-false-value="0">'); |
480 | 636 |
481 scope.apply(() { | 637 scope.apply(() { |
482 scope.context['model'] = 1; | 638 scope.context['model'] = 1; |
483 }); | 639 }); |
484 expect(element.checked).toBe(true); | 640 expect(element.checked).toBe(true); |
485 | 641 |
486 scope.apply(() { | 642 scope.apply(() { |
487 scope.context['model'] = 0; | 643 scope.context['model'] = 0; |
488 }); | 644 }); |
489 expect(element.checked).toBe(false); | 645 expect(element.checked).toBe(false); |
490 | 646 |
491 element.checked = true; | 647 element.checked = true; |
492 _.triggerEvent(element, 'change'); | 648 _.triggerEvent(element, 'change'); |
493 expect(scope.context['model']).toBe(1); | 649 expect(scope.context['model']).toBe(1); |
494 | 650 |
495 element.checked = false; | 651 element.checked = false; |
496 _.triggerEvent(element, 'change'); | 652 _.triggerEvent(element, 'change'); |
497 expect(scope.context['model']).toBe(0); | 653 expect(scope.context['model']).toBe(0); |
498 })); | 654 }); |
499 | 655 |
500 | 656 it('should allow non boolean values like null, 0, 1', (Scope scope) { |
501 it('should allow non boolean values like null, 0, 1', inject((Scope scope)
{ | |
502 var element = _.compile('<input type="checkbox" ng-model="model">'); | 657 var element = _.compile('<input type="checkbox" ng-model="model">'); |
503 | 658 |
504 scope.apply(() { | 659 scope.apply(() { |
505 scope.context['model'] = 0; | 660 scope.context['model'] = 0; |
506 }); | 661 }); |
507 expect(element.checked).toBe(false); | 662 expect(element.checked).toBe(false); |
508 | 663 |
509 scope.apply(() { | 664 scope.apply(() { |
510 scope.context['model'] = 1; | 665 scope.context['model'] = 1; |
511 }); | 666 }); |
512 expect(element.checked).toBe(true); | 667 expect(element.checked).toBe(true); |
513 | 668 |
514 scope.apply(() { | 669 scope.apply(() { |
515 scope.context['model'] = null; | 670 scope.context['model'] = null; |
516 }); | 671 }); |
517 expect(element.checked).toBe(false); | 672 expect(element.checked).toBe(false); |
518 })); | 673 }); |
519 | 674 |
520 | 675 it('should update model from the input value', (Scope scope) { |
521 it('should update model from the input value', inject((Scope scope) { | |
522 var element = _.compile('<input type="checkbox" ng-model="model">'); | 676 var element = _.compile('<input type="checkbox" ng-model="model">'); |
523 | 677 |
524 element.checked = true; | 678 element.checked = true; |
525 _.triggerEvent(element, 'change'); | 679 _.triggerEvent(element, 'change'); |
526 expect(scope.context['model']).toBe(true); | 680 expect(scope.context['model']).toBe(true); |
527 | 681 |
528 element.checked = false; | 682 element.checked = false; |
529 _.triggerEvent(element, 'change'); | 683 _.triggerEvent(element, 'change'); |
530 expect(scope.context['model']).toBe(false); | 684 expect(scope.context['model']).toBe(false); |
531 })); | 685 }); |
| 686 |
| 687 it('should update model from the input using ng-true-value/false', (Scope
scope) { |
| 688 var element = _.compile('<input type="checkbox" ng-model="model" ' |
| 689 'ng-true-value="yes" ng-false-value="no">'); |
| 690 scope.apply(() { |
| 691 scope.context['yes'] = 'yes sir!'; |
| 692 scope.context['no'] = 'no, sorry'; |
| 693 }); |
| 694 |
| 695 element.checked = true; |
| 696 _.triggerEvent(element, 'change'); |
| 697 expect(scope.context['model']).toEqual('yes sir!'); |
| 698 |
| 699 element.checked = false; |
| 700 _.triggerEvent(element, 'change'); |
| 701 expect(scope.context['model']).toEqual('no, sorry'); |
| 702 }); |
| 703 |
| 704 it('should only render the input value upon the next digest', (Scope scope
) { |
| 705 _.compile('<input type="checkbox" ng-model="model" probe="p">'); |
| 706 Probe probe = _.rootScope.context['p']; |
| 707 var ngModel = probe.directive(NgModel); |
| 708 InputElement inputElement = probe.element; |
| 709 |
| 710 ngModel.render('xyz'); |
| 711 scope.context['model'] = true; |
| 712 |
| 713 expect(inputElement.checked).toBe(false); |
| 714 |
| 715 scope.apply(); |
| 716 |
| 717 expect(inputElement.checked).toBe(true); |
| 718 }); |
532 }); | 719 }); |
533 | 720 |
534 describe('textarea', () { | 721 describe('textarea', () { |
535 it('should update textarea value from model', inject(() { | 722 it('should update textarea value from model', () { |
536 _.compile('<textarea ng-model="model">'); | 723 _.compile('<textarea ng-model="model">'); |
537 _.rootScope.apply(); | 724 _.rootScope.apply(); |
538 | 725 |
539 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | 726 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
540 | 727 |
541 _.rootScope.apply('model = "misko"'); | 728 _.rootScope.apply('model = "misko"'); |
542 expect((_.rootElement as dom.TextAreaElement).value).toEqual('misko'); | 729 expect((_.rootElement as dom.TextAreaElement).value).toEqual('misko'); |
543 })); | 730 }); |
544 | 731 |
545 it('should render null as the empty string', inject(() { | 732 it('should render null as the empty string', () { |
546 _.compile('<textarea ng-model="model">'); | 733 _.compile('<textarea ng-model="model">'); |
547 _.rootScope.apply(); | 734 _.rootScope.apply(); |
548 | 735 |
549 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | 736 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
550 | 737 |
551 _.rootScope.apply('model = null'); | 738 _.rootScope.apply('model = null'); |
552 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | 739 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
553 })); | 740 }); |
554 | 741 |
555 it('should update model from the input value', inject(() { | 742 it('should update model from the input value', () { |
556 _.compile('<textarea ng-model="model" probe="p">'); | 743 _.compile('<textarea ng-model="model" probe="p">'); |
557 Probe probe = _.rootScope.context['p']; | 744 Probe probe = _.rootScope.context['p']; |
558 var ngModel = probe.directive(NgModel); | 745 var ngModel = probe.directive(NgModel); |
559 TextAreaElement element = probe.element; | 746 TextAreaElement element = probe.element; |
560 | 747 |
561 element.value = 'abc'; | 748 element.value = 'abc'; |
562 _.triggerEvent(element, 'change'); | 749 _.triggerEvent(element, 'change'); |
563 expect(_.rootScope.context['model']).toEqual('abc'); | 750 expect(_.rootScope.context['model']).toEqual('abc'); |
564 | 751 |
565 element.value = 'def'; | 752 element.value = 'def'; |
566 var textarea = probe.directive(InputTextLikeDirective); | 753 var textarea = probe.directive(InputTextLike); |
567 textarea.processValue(); | 754 textarea.processValue(); |
568 expect(_.rootScope.context['model']).toEqual('def'); | 755 expect(_.rootScope.context['model']).toEqual('def'); |
569 | 756 |
570 })); | 757 }); |
571 | 758 |
572 // NOTE(deboer): This test passes on Dartium, but fails in the content_she
ll. | 759 // NOTE(deboer): This test passes on Dartium, but fails in the content_she
ll. |
573 // The Dart team is looking into this bug. | 760 // The Dart team is looking into this bug. |
574 xit('should write to input only if value is different', inject((Injector i
, AstParser parser) { | 761 xit('should write to input only if value is different', |
| 762 (Injector i, Animate animate) { |
| 763 |
575 var scope = _.rootScope; | 764 var scope = _.rootScope; |
576 var element = new dom.TextAreaElement(); | 765 var element = new dom.TextAreaElement(); |
| 766 var ngElement = new NgElement(element, scope, animate); |
| 767 |
577 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 768 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
578 nodeAttrs['ng-model'] = 'model'; | 769 nodeAttrs['ng-model'] = 'model'; |
579 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); | 770 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), |
| 771 nodeAttrs, new Animate()); |
580 dom.querySelector('body').append(element); | 772 dom.querySelector('body').append(element); |
581 var input = new InputTextLikeDirective(element, model, scope); | 773 var input = new InputTextLike(element, model, scope); |
582 | 774 |
583 element | 775 element |
584 ..value = 'abc' | 776 ..value = 'abc' |
585 ..selectionStart = 1 | 777 ..selectionStart = 1 |
586 ..selectionEnd = 2; | 778 ..selectionEnd = 2; |
587 | 779 |
588 model.render('abc'); | 780 model.render('abc'); |
589 | 781 |
590 expect(element.value).toEqual('abc'); | 782 expect(element.value).toEqual('abc'); |
591 expect(element.selectionStart).toEqual(1); | 783 expect(element.selectionStart).toEqual(1); |
592 expect(element.selectionEnd).toEqual(2); | 784 expect(element.selectionEnd).toEqual(2); |
593 | 785 |
594 model.render('xyz'); | 786 model.render('xyz'); |
595 | 787 |
596 // Setting the value on a textarea doesn't update the selection the way
it | 788 // Setting the value on a textarea doesn't update the selection the way
it |
597 // does on input elements. This stays unchanged. | 789 // does on input elements. This stays unchanged. |
598 expect(element.value).toEqual('xyz'); | 790 expect(element.value).toEqual('xyz'); |
599 expect(element.selectionStart).toEqual(0); | 791 expect(element.selectionStart).toEqual(0); |
600 expect(element.selectionEnd).toEqual(0); | 792 expect(element.selectionEnd).toEqual(0); |
601 })); | 793 }); |
| 794 |
| 795 it('should only render the input value upon the next digest', (Scope scope
) { |
| 796 _.compile('<textarea ng-model="model" probe="p"></textarea>'); |
| 797 Probe probe = _.rootScope.context['p']; |
| 798 var ngModel = probe.directive(NgModel); |
| 799 TextAreaElement inputElement = probe.element; |
| 800 |
| 801 ngModel.render('xyz'); |
| 802 scope.context['model'] = 'xyz'; |
| 803 |
| 804 expect(inputElement.value).not.toEqual('xyz'); |
| 805 |
| 806 scope.apply(); |
| 807 |
| 808 expect(inputElement.value).toEqual('xyz'); |
| 809 }); |
602 }); | 810 }); |
603 | 811 |
604 describe('type="radio"', () { | 812 describe('type="radio"', () { |
605 it('should update input value from model', inject(() { | 813 it('should update input value from model', () { |
606 _.compile('<input type="radio" name="color" value="red" ng-model="color"
probe="r">' + | 814 _.compile('<input type="radio" name="color" value="red" ng-model="color"
probe="r">' + |
607 '<input type="radio" name="color" value="green" ng-model="colo
r" probe="g">' + | 815 '<input type="radio" name="color" value="green" ng-model="colo
r" probe="g">' + |
608 '<input type="radio" name="color" value="blue" ng-model="color
" probe="b">'); | 816 '<input type="radio" name="color" value="blue" ng-model="color
" probe="b">'); |
609 _.rootScope.apply(); | 817 _.rootScope.apply(); |
610 | 818 |
611 RadioButtonInputElement redBtn = _.rootScope.context['r'].element; | 819 RadioButtonInputElement redBtn = _.rootScope.context['r'].element; |
612 RadioButtonInputElement greenBtn = _.rootScope.context['g'].element; | 820 RadioButtonInputElement greenBtn = _.rootScope.context['g'].element; |
613 RadioButtonInputElement blueBtn = _.rootScope.context['b'].element; | 821 RadioButtonInputElement blueBtn = _.rootScope.context['b'].element; |
614 | 822 |
615 expect(redBtn.checked).toBe(false); | 823 expect(redBtn.checked).toBe(false); |
(...skipping 20 matching lines...) Expand all Loading... |
636 expect(_.rootScope.context['color']).toEqual('red'); | 844 expect(_.rootScope.context['color']).toEqual('red'); |
637 expect(redBtn.checked).toBe(true); | 845 expect(redBtn.checked).toBe(true); |
638 expect(greenBtn.checked).toBe(false); | 846 expect(greenBtn.checked).toBe(false); |
639 expect(blueBtn.checked).toBe(false); | 847 expect(blueBtn.checked).toBe(false); |
640 | 848 |
641 _.triggerEvent(greenBtn, 'click'); | 849 _.triggerEvent(greenBtn, 'click'); |
642 expect(_.rootScope.context['color']).toEqual('green'); | 850 expect(_.rootScope.context['color']).toEqual('green'); |
643 expect(redBtn.checked).toBe(false); | 851 expect(redBtn.checked).toBe(false); |
644 expect(greenBtn.checked).toBe(true); | 852 expect(greenBtn.checked).toBe(true); |
645 expect(blueBtn.checked).toBe(false); | 853 expect(blueBtn.checked).toBe(false); |
646 })); | 854 }); |
647 | 855 |
648 it('should support ng-value', () { | 856 it('should support ng-value', () { |
649 _.compile('<input type="radio" name="color" ng-value="red" ng-model="col
or" probe="r">' + | 857 _.compile('<input type="radio" name="color" ng-value="red" ng-model="col
or" probe="r">' + |
650 '<input type="radio" name="color" ng-value="green" ng-model="c
olor" probe="g">' + | 858 '<input type="radio" name="color" ng-value="green" ng-model="c
olor" probe="g">' + |
651 '<input type="radio" name="color" ng-value="blue" ng-model="co
lor" probe="b">'); | 859 '<input type="radio" name="color" ng-value="blue" ng-model="co
lor" probe="b">'); |
652 | 860 |
653 var red = {'name': 'RED'}; | 861 var red = {'name': 'RED'}; |
654 var green = {'name': 'GREEN'}; | 862 var green = {'name': 'GREEN'}; |
655 var blue = {'name': 'BLUE'}; | 863 var blue = {'name': 'BLUE'}; |
656 _.rootScope.context | 864 _.rootScope.context |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 expect(greenBtn.checked).toBe(false); | 900 expect(greenBtn.checked).toBe(false); |
693 expect(blueBtn.checked).toBe(false); | 901 expect(blueBtn.checked).toBe(false); |
694 | 902 |
695 _.triggerEvent(greenBtn, 'click'); | 903 _.triggerEvent(greenBtn, 'click'); |
696 expect(_.rootScope.context['color']).toEqual(green); | 904 expect(_.rootScope.context['color']).toEqual(green); |
697 expect(redBtn.checked).toBe(false); | 905 expect(redBtn.checked).toBe(false); |
698 expect(greenBtn.checked).toBe(true); | 906 expect(greenBtn.checked).toBe(true); |
699 expect(blueBtn.checked).toBe(false); | 907 expect(blueBtn.checked).toBe(false); |
700 }); | 908 }); |
701 | 909 |
702 it('should render as dirty when checked', inject((Scope scope) { | 910 it('should render as dirty when checked', (Scope scope) { |
703 var element = _.compile( | 911 var element = _.compile( |
704 '<div>' + | 912 '<div>' + |
705 ' <input type="radio" id="on" ng-model="my_model" probe="i" value="on
" />' + | 913 ' <input type="radio" id="on" ng-model="my_model" probe="i" value="on
" />' + |
706 ' <input type="radio" id="off" ng-model="my_model" probe="j" value="o
ff" />' + | 914 ' <input type="radio" id="off" ng-model="my_model" probe="j" value="o
ff" />' + |
707 '</div>' | 915 '</div>' |
708 ); | 916 ); |
709 Probe probe = _.rootScope.context['i']; | 917 Probe probe = _.rootScope.context['i']; |
710 | 918 |
711 var model = probe.directive(NgModel); | 919 var model = probe.directive(NgModel); |
712 | 920 |
713 var input1 = element.querySelector("#on"); | 921 var input1 = element.querySelector("#on"); |
714 var input2 = element.querySelector("#off"); | 922 var input2 = element.querySelector("#off"); |
715 | 923 |
| 924 scope.apply(); |
| 925 |
716 expect(model.pristine).toEqual(true); | 926 expect(model.pristine).toEqual(true); |
717 expect(model.dirty).toEqual(false); | 927 expect(model.dirty).toEqual(false); |
718 | 928 |
719 expect(input1.classes.contains("ng-dirty")).toBe(false); | 929 expect(input1.classes.contains("ng-dirty")).toBe(false); |
720 expect(input2.classes.contains("ng-dirty")).toBe(false); | 930 expect(input2.classes.contains("ng-dirty")).toBe(false); |
721 expect(input1.classes.contains("ng-pristine")).toBe(true); | 931 expect(input1.classes.contains("ng-pristine")).toBe(true); |
722 expect(input1.classes.contains("ng-pristine")).toBe(true); | 932 expect(input1.classes.contains("ng-pristine")).toBe(true); |
723 | 933 |
724 input1.checked = true; | 934 input1.checked = true; |
725 _.triggerEvent(input1, 'click'); | 935 _.triggerEvent(input1, 'click'); |
| 936 scope.apply(); |
726 | 937 |
727 expect(model.pristine).toEqual(false); | 938 expect(model.pristine).toEqual(false); |
728 expect(model.dirty).toEqual(true); | 939 expect(model.dirty).toEqual(true); |
729 | 940 |
730 input1.checked = false; | 941 input1.checked = false; |
731 input2.checked = true; | 942 input2.checked = true; |
732 _.triggerEvent(input2, 'click'); | 943 _.triggerEvent(input2, 'click'); |
| 944 scope.apply(); |
733 | 945 |
734 expect(input1.classes.contains("ng-dirty")).toBe(true); | 946 expect(input1.classes.contains("ng-dirty")).toBe(true); |
735 expect(input2.classes.contains("ng-dirty")).toBe(true); | 947 expect(input2.classes.contains("ng-dirty")).toBe(true); |
736 expect(input1.classes.contains("ng-pristine")).toBe(false); | 948 expect(input1.classes.contains("ng-pristine")).toBe(false); |
737 expect(input1.classes.contains("ng-pristine")).toBe(false); | 949 expect(input1.classes.contains("ng-pristine")).toBe(false); |
738 })); | 950 }); |
| 951 |
| 952 it('should only render the input value upon the next digest', (Scope scope
) { |
| 953 var element = _.compile( |
| 954 '<div>' + |
| 955 ' <input type="radio" id="on" ng-model="model" probe="i" value="on" /
>' + |
| 956 ' <input type="radio" id="off" ng-model="model" probe="j" value="off"
/>' + |
| 957 '</div>' |
| 958 ); |
| 959 |
| 960 Probe probe1 = _.rootScope.context['i']; |
| 961 var ngModel1 = probe1.directive(NgModel); |
| 962 InputElement inputElement1 = probe1.element; |
| 963 |
| 964 Probe probe2 = _.rootScope.context['j']; |
| 965 var ngModel2 = probe2.directive(NgModel); |
| 966 InputElement inputElement2 = probe2.element; |
| 967 |
| 968 ngModel1.render('on'); |
| 969 scope.context['model'] = 'on'; |
| 970 |
| 971 expect(inputElement1.checked).toBe(false); |
| 972 expect(inputElement2.checked).toBe(false); |
| 973 |
| 974 scope.apply(); |
| 975 |
| 976 expect(inputElement1.checked).toBe(true); |
| 977 expect(inputElement2.checked).toBe(false); |
| 978 }); |
739 }); | 979 }); |
740 | 980 |
741 describe('type="search"', () { | 981 describe('type="search"', () { |
742 it('should update input value from model', inject(() { | 982 it('should update input value from model', () { |
743 _.compile('<input type="search" ng-model="model">'); | 983 _.compile('<input type="search" ng-model="model">'); |
744 _.rootScope.apply(); | 984 _.rootScope.apply(); |
745 | 985 |
746 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 986 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
747 | 987 |
748 _.rootScope.apply('model = "matias"'); | 988 _.rootScope.apply('model = "matias"'); |
749 expect((_.rootElement as dom.InputElement).value).toEqual('matias'); | 989 expect((_.rootElement as dom.InputElement).value).toEqual('matias'); |
750 })); | 990 }); |
751 | 991 |
752 it('should render null as the empty string', inject(() { | 992 it('should render null as the empty string', () { |
753 _.compile('<input type="search" ng-model="model">'); | 993 _.compile('<input type="search" ng-model="model">'); |
754 _.rootScope.apply(); | 994 _.rootScope.apply(); |
755 | 995 |
756 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 996 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
757 | 997 |
758 _.rootScope.apply('model = null'); | 998 _.rootScope.apply('model = null'); |
759 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 999 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
760 })); | 1000 }); |
761 | 1001 |
762 it('should update model from the input value', inject(() { | 1002 it('should update model from the input value', () { |
763 _.compile('<input type="search" ng-model="model" probe="p">'); | 1003 _.compile('<input type="search" ng-model="model" probe="p">'); |
764 Probe probe = _.rootScope.context['p']; | 1004 Probe probe = _.rootScope.context['p']; |
765 var ngModel = probe.directive(NgModel); | 1005 var ngModel = probe.directive(NgModel); |
766 InputElement inputElement = probe.element; | 1006 InputElement inputElement = probe.element; |
767 | 1007 |
768 inputElement.value = 'xzy'; | 1008 inputElement.value = 'xzy'; |
769 _.triggerEvent(inputElement, 'change'); | 1009 _.triggerEvent(inputElement, 'change'); |
770 expect(_.rootScope.context['model']).toEqual('xzy'); | 1010 expect(_.rootScope.context['model']).toEqual('xzy'); |
771 | 1011 |
772 inputElement.value = '123'; | 1012 inputElement.value = '123'; |
773 var input = probe.directive(InputTextLikeDirective); | 1013 var input = probe.directive(InputTextLike); |
774 input.processValue(); | 1014 input.processValue(); |
775 expect(_.rootScope.context['model']).toEqual('123'); | 1015 expect(_.rootScope.context['model']).toEqual('123'); |
776 })); | 1016 }); |
| 1017 |
| 1018 it('should only render the input value upon the next digest', (Scope scope
) { |
| 1019 _.compile('<input type="search" ng-model="model" probe="p">'); |
| 1020 Probe probe = _.rootScope.context['p']; |
| 1021 var ngModel = probe.directive(NgModel); |
| 1022 InputElement inputElement = probe.element; |
| 1023 |
| 1024 ngModel.render('xyz'); |
| 1025 scope.context['model'] = 'xyz'; |
| 1026 |
| 1027 expect(inputElement.value).not.toEqual('xyz'); |
| 1028 |
| 1029 scope.apply(); |
| 1030 |
| 1031 expect(inputElement.value).toEqual('xyz'); |
| 1032 }); |
777 }); | 1033 }); |
778 | 1034 |
779 describe('contenteditable', () { | 1035 describe('contenteditable', () { |
780 it('should update content from model', inject(() { | 1036 it('should update content from model', () { |
781 _.compile('<p contenteditable ng-model="model">'); | 1037 _.compile('<p contenteditable ng-model="model">'); |
782 _.rootScope.apply(); | 1038 _.rootScope.apply(); |
783 | 1039 |
784 expect(_.rootElement.text).toEqual(''); | 1040 expect(_.rootElement.text).toEqual(''); |
785 | 1041 |
786 _.rootScope.apply('model = "misko"'); | 1042 _.rootScope.apply('model = "misko"'); |
787 expect(_.rootElement.text).toEqual('misko'); | 1043 expect(_.rootElement.text).toEqual('misko'); |
788 })); | 1044 }); |
789 | 1045 |
790 it('should update model from the input value', inject(() { | 1046 it('should update model from the input value', () { |
791 _.compile('<p contenteditable ng-model="model">'); | 1047 _.compile('<p contenteditable ng-model="model">'); |
792 Element element = _.rootElement; | 1048 Element element = _.rootElement; |
793 | 1049 |
794 element.innerHtml = 'abc'; | 1050 element.innerHtml = 'abc'; |
795 _.triggerEvent(element, 'change'); | 1051 _.triggerEvent(element, 'change'); |
796 expect(_.rootScope.context['model']).toEqual('abc'); | 1052 expect(_.rootScope.context['model']).toEqual('abc'); |
797 | 1053 |
798 element.innerHtml = 'def'; | 1054 element.innerHtml = 'def'; |
799 var input = ngInjector(element).get(ContentEditableDirective); | 1055 var input = ngInjector(element).get(ContentEditable); |
800 input.processValue(); | 1056 input.processValue(); |
801 expect(_.rootScope.context['model']).toEqual('def'); | 1057 expect(_.rootScope.context['model']).toEqual('def'); |
802 })); | 1058 }); |
| 1059 |
| 1060 it('should only render the input value upon the next digest', (Scope scope
) { |
| 1061 _.compile('<div contenteditable ng-model="model" probe="p"></div>'); |
| 1062 Probe probe = _.rootScope.context['p']; |
| 1063 var ngModel = probe.directive(NgModel); |
| 1064 Element element = probe.element; |
| 1065 |
| 1066 ngModel.render('xyz'); |
| 1067 scope.context['model'] = 'xyz'; |
| 1068 |
| 1069 expect(element.innerHtml).not.toEqual('xyz'); |
| 1070 |
| 1071 scope.apply(); |
| 1072 |
| 1073 expect(element.innerHtml).toEqual('xyz'); |
| 1074 }); |
803 }); | 1075 }); |
804 | 1076 |
805 describe('pristine / dirty', () { | 1077 describe('pristine / dirty', () { |
806 it('should be set to pristine by default', inject((Scope scope) { | 1078 it('should be set to pristine by default', (Scope scope) { |
807 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 1079 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
808 Probe probe = _.rootScope.context['i']; | 1080 Probe probe = _.rootScope.context['i']; |
809 var model = probe.directive(NgModel); | 1081 var model = probe.directive(NgModel); |
810 | 1082 |
811 expect(model.pristine).toEqual(true); | 1083 expect(model.pristine).toEqual(true); |
812 expect(model.dirty).toEqual(false); | 1084 expect(model.dirty).toEqual(false); |
813 })); | 1085 }); |
814 | 1086 |
815 it('should add and remove the correct CSS classes when set to dirty and to
pristine', inject((Scope scope) { | 1087 it('should add and remove the correct CSS classes when set to dirty and to
pristine', (Scope scope) { |
816 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 1088 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
817 Probe probe = _.rootScope.context['i']; | 1089 Probe probe = _.rootScope.context['i']; |
818 NgModel model = probe.directive(NgModel); | 1090 NgModel model = probe.directive(NgModel); |
819 InputElement element = probe.element; | 1091 InputElement element = probe.element; |
820 | 1092 |
821 model.dirty = true; | 1093 model.addInfo('ng-dirty'); |
| 1094 scope.apply(); |
| 1095 |
822 expect(model.pristine).toEqual(false); | 1096 expect(model.pristine).toEqual(false); |
823 expect(model.dirty).toEqual(true); | 1097 expect(model.dirty).toEqual(true); |
824 expect(element.classes.contains('ng-pristine')).toBe(false); | 1098 expect(element).not.toHaveClass('ng-pristine'); |
825 expect(element.classes.contains('ng-dirty')).toBe(true); | 1099 expect(element).toHaveClass('ng-dirty'); |
826 | 1100 |
827 model.pristine = true; | 1101 model.removeInfo('ng-dirty'); |
| 1102 scope.apply(); |
| 1103 |
828 expect(model.pristine).toEqual(true); | 1104 expect(model.pristine).toEqual(true); |
829 expect(model.dirty).toEqual(false); | 1105 expect(model.dirty).toEqual(false); |
830 expect(element.classes.contains('ng-pristine')).toBe(true); | 1106 expect(element).toHaveClass('ng-pristine'); |
831 expect(element.classes.contains('ng-dirty')).toBe(false); | 1107 expect(element).not.toHaveClass('ng-dirty'); |
832 })); | 1108 }); |
833 | 1109 |
834 it('should render the parent form/fieldset as dirty but not the other mode
ls', inject((Scope scope) { | 1110 // TODO(matias): figure out why the 2nd apply is optional |
| 1111 it('should render the parent form/fieldset as dirty but not the other mode
ls', |
| 1112 (Scope scope) { |
| 1113 |
835 _.compile('<form name="myForm">' + | 1114 _.compile('<form name="myForm">' + |
836 ' <fieldset name="myFieldset">' + | 1115 ' <fieldset name="myFieldset">' + |
837 ' <input type="text" ng-model="my_model1" probe="myModel1"
/>' + | 1116 ' <input type="text" ng-model="my_model1" probe="myModel1"
/>' + |
838 ' <input type="text" ng-model="my_model2" probe="myModel2"
/>' + | 1117 ' <input type="text" ng-model="my_model2" probe="myModel2"
/>' + |
839 ' </fieldset>' + | 1118 ' </fieldset>' + |
840 '</form>'); | 1119 '</form>'); |
841 | 1120 |
| 1121 var formElement = _.rootScope.context['myForm'].element.node; |
| 1122 var fieldsetElement = _.rootScope.context['myFieldset'].element.node; |
842 var inputElement1 = _.rootScope.context['myModel1'].element; | 1123 var inputElement1 = _.rootScope.context['myModel1'].element; |
843 var inputElement2 = _.rootScope.context['myModel2'].element; | 1124 var inputElement2 = _.rootScope.context['myModel2'].element; |
844 var formElement = _.rootScope.context['myForm'].element; | |
845 var fieldsetElement = _.rootScope.context['myFieldset'].element; | |
846 | 1125 |
847 expect(formElement.classes.contains('ng-pristine')).toBe(true); | 1126 scope.apply(); |
848 expect(formElement.classes.contains('ng-dirty')).toBe(false); | |
849 | 1127 |
850 expect(fieldsetElement.classes.contains('ng-pristine')).toBe(true); | 1128 expect(formElement).toHaveClass('ng-pristine'); |
851 expect(fieldsetElement.classes.contains('ng-dirty')).toBe(false); | 1129 expect(formElement).not.toHaveClass('ng-dirty'); |
852 | 1130 |
853 expect(inputElement1.classes.contains('ng-pristine')).toBe(true); | 1131 expect(fieldsetElement).toHaveClass('ng-pristine'); |
854 expect(inputElement1.classes.contains('ng-dirty')).toBe(false); | 1132 expect(fieldsetElement).not.toHaveClass('ng-dirty'); |
855 | 1133 |
856 expect(inputElement2.classes.contains('ng-pristine')).toBe(true); | 1134 expect(inputElement1).toHaveClass('ng-pristine'); |
857 expect(inputElement2.classes.contains('ng-dirty')).toBe(false); | 1135 expect(inputElement1).not.toHaveClass('ng-dirty'); |
| 1136 |
| 1137 expect(inputElement2).toHaveClass('ng-pristine'); |
| 1138 expect(inputElement2).not.toHaveClass('ng-dirty'); |
858 | 1139 |
859 inputElement1.value = '...hi...'; | 1140 inputElement1.value = '...hi...'; |
860 _.triggerEvent(inputElement1, 'change'); | 1141 _.triggerEvent(inputElement1, 'change'); |
| 1142 scope.apply(); |
861 | 1143 |
862 expect(formElement.classes.contains('ng-pristine')).toBe(false); | 1144 expect(formElement).not.toHaveClass('ng-pristine'); |
863 expect(formElement.classes.contains('ng-dirty')).toBe(true); | 1145 expect(formElement).toHaveClass('ng-dirty'); |
864 | 1146 |
865 expect(fieldsetElement.classes.contains('ng-pristine')).toBe(false); | 1147 expect(fieldsetElement).not.toHaveClass('ng-pristine'); |
866 expect(fieldsetElement.classes.contains('ng-dirty')).toBe(true); | 1148 expect(fieldsetElement).toHaveClass('ng-dirty'); |
867 | 1149 |
868 expect(inputElement1.classes.contains('ng-pristine')).toBe(false); | 1150 expect(inputElement1).not.toHaveClass('ng-pristine'); |
869 expect(inputElement1.classes.contains('ng-dirty')).toBe(true); | 1151 expect(inputElement1).toHaveClass('ng-dirty'); |
870 | 1152 |
871 expect(inputElement2.classes.contains('ng-pristine')).toBe(true); | 1153 expect(inputElement2).toHaveClass('ng-pristine'); |
872 expect(inputElement2.classes.contains('ng-dirty')).toBe(false); | 1154 expect(inputElement2).not.toHaveClass('ng-dirty'); |
873 })); | 1155 }); |
874 }); | 1156 }); |
875 | 1157 |
876 describe('validation', () { | 1158 describe('validation', () { |
877 it('should happen automatically when the scope changes', inject((Scope sco
pe) { | 1159 it('should happen automatically when the scope changes', (Scope scope) { |
878 _.compile('<input type="text" ng-model="model" probe="i" required>'); | 1160 _.compile('<input type="text" ng-model="model" probe="i" required>'); |
879 _.rootScope.apply(); | 1161 _.rootScope.apply(); |
880 | 1162 |
881 Probe probe = _.rootScope.context['i']; | 1163 Probe probe = _.rootScope.context['i']; |
882 var model = probe.directive(NgModel); | 1164 var model = probe.directive(NgModel); |
883 | 1165 |
884 expect(model.invalid).toBe(true); | 1166 expect(model.invalid).toBe(true); |
885 expect(model.valid).toBe(false); | 1167 expect(model.valid).toBe(false); |
886 | 1168 |
887 _.rootScope.apply('model = "viljami"'); | 1169 _.rootScope.apply('model = "viljami"'); |
888 | 1170 |
889 expect(model.invalid).toBe(false); | 1171 expect(model.invalid).toBe(false); |
890 expect(model.valid).toBe(true); | 1172 expect(model.valid).toBe(true); |
891 })); | 1173 }); |
892 | 1174 |
893 it('should happen automatically upon user input via the onInput event', in
ject(() { | 1175 it('should happen automatically upon user input via the onInput event', ()
{ |
894 _.compile('<input type="text" ng-model="model" probe="i" required>'); | 1176 _.compile('<input type="text" ng-model="model" probe="i" required>'); |
| 1177 _.rootScope.apply(); |
895 | 1178 |
896 Probe probe = _.rootScope.context['i']; | 1179 Probe probe = _.rootScope.context['i']; |
897 var model = probe.directive(NgModel); | 1180 var model = probe.directive(NgModel); |
898 InputElement inputElement = model.element; | 1181 InputElement inputElement = model.element.node; |
899 | 1182 |
900 expect(model.invalid).toBe(true); | 1183 expect(model.invalid).toBe(true); |
901 expect(model.valid).toBe(false); | 1184 expect(model.valid).toBe(false); |
902 | 1185 |
903 inputElement.value = 'some value'; | 1186 inputElement.value = 'some value'; |
904 _.triggerEvent(inputElement, 'input'); | 1187 _.triggerEvent(inputElement, 'input'); |
905 | 1188 |
906 expect(model.invalid).toBe(false); | 1189 expect(model.invalid).toBe(false); |
907 expect(model.valid).toBe(true); | 1190 expect(model.valid).toBe(true); |
908 })); | 1191 }); |
909 }); | 1192 }); |
910 | 1193 |
911 describe('valid / invalid', () { | 1194 describe('valid / invalid', () { |
912 it('should add and remove the correct flags when set to valid and to inval
id', inject((Scope scope) { | 1195 it('should add and remove the correct flags when set to valid and to inval
id', (Scope scope) { |
913 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 1196 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
914 Probe probe = _.rootScope.context['i']; | 1197 Probe probe = _.rootScope.context['i']; |
915 var model = probe.directive(NgModel); | 1198 var model = probe.directive(NgModel); |
916 InputElement element = probe.element; | 1199 InputElement element = probe.element; |
917 | 1200 |
918 model.invalid = true; | 1201 model.addError('ng-required'); |
| 1202 model.validate(); |
| 1203 scope.apply(); |
| 1204 |
919 expect(model.valid).toEqual(false); | 1205 expect(model.valid).toEqual(false); |
920 expect(model.invalid).toEqual(true); | 1206 expect(model.invalid).toEqual(true); |
921 expect(element.classes.contains('ng-valid')).toBe(false); | 1207 //expect(element).not.toHaveClass('ng-valid'); |
922 expect(element.classes.contains('ng-invalid')).toBe(true); | 1208 expect(element).toHaveClass('ng-invalid'); |
923 | 1209 |
924 model.valid = true; | 1210 model.removeError('ng-required'); |
| 1211 model.validate(); |
| 1212 scope.apply(); |
| 1213 |
925 expect(model.valid).toEqual(true); | 1214 expect(model.valid).toEqual(true); |
926 expect(model.invalid).toEqual(false); | 1215 expect(model.invalid).toEqual(false); |
927 expect(element.classes.contains('ng-invalid')).toBe(false); | 1216 expect(element).not.toHaveClass('ng-invalid'); |
928 expect(element.classes.contains('ng-valid')).toBe(true); | 1217 // expect(element).toHaveClass('ng-valid'); |
929 })); | 1218 }); |
930 | 1219 |
931 it('should set the validity with respect to all existing validations when
setValidity() is used', inject((Scope scope) { | 1220 it('should set the validity with respect to all existing validations when
setValidity() is used', (Scope scope) { |
932 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 1221 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
933 Probe probe = _.rootScope.context['i']; | 1222 Probe probe = _.rootScope.context['i']; |
934 var model = probe.directive(NgModel); | 1223 var model = probe.directive(NgModel); |
935 | 1224 |
936 model.setValidity("required", false); | 1225 model.addError("required"); |
937 expect(model.valid).toEqual(false); | 1226 expect(model.valid).toEqual(false); |
938 expect(model.invalid).toEqual(true); | 1227 expect(model.invalid).toEqual(true); |
939 | 1228 |
940 model.setValidity("format", false); | 1229 model.addError("format"); |
941 expect(model.valid).toEqual(false); | 1230 expect(model.valid).toEqual(false); |
942 expect(model.invalid).toEqual(true); | 1231 expect(model.invalid).toEqual(true); |
943 | 1232 |
944 model.setValidity("format", true); | 1233 model.removeError("format"); |
945 expect(model.valid).toEqual(false); | 1234 expect(model.valid).toEqual(false); |
946 expect(model.invalid).toEqual(true); | 1235 expect(model.invalid).toEqual(true); |
947 | 1236 |
948 model.setValidity("required", true); | 1237 model.removeError("required"); |
949 expect(model.valid).toEqual(true); | 1238 expect(model.valid).toEqual(true); |
950 expect(model.invalid).toEqual(false); | 1239 expect(model.invalid).toEqual(false); |
951 })); | 1240 }); |
952 | 1241 |
953 it('should register each error only once when invalid', inject((Scope scop
e) { | 1242 it('should register each error only once when invalid', (Scope scope) { |
954 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 1243 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
955 Probe probe = _.rootScope.context['i']; | 1244 Probe probe = _.rootScope.context['i']; |
956 var model = probe.directive(NgModel); | 1245 var model = probe.directive(NgModel); |
957 | 1246 |
958 model.setValidity("distinct-error", false); | 1247 model.addError("distinct-error"); |
959 expect(model.valid).toEqual(false); | 1248 expect(model.valid).toEqual(false); |
960 expect(model.invalid).toEqual(true); | 1249 expect(model.invalid).toEqual(true); |
961 | 1250 |
962 model.setValidity("distinct-error", false); | 1251 model.addError("distinct-error"); |
963 expect(model.valid).toEqual(false); | 1252 expect(model.valid).toEqual(false); |
964 expect(model.invalid).toEqual(true); | 1253 expect(model.invalid).toEqual(true); |
965 | 1254 |
966 model.setValidity("distinct-error", true); | 1255 model.removeError("distinct-error"); |
967 expect(model.valid).toEqual(true); | 1256 expect(model.valid).toEqual(true); |
968 expect(model.invalid).toEqual(false); | 1257 expect(model.invalid).toEqual(false); |
969 })); | 1258 }); |
| 1259 }); |
| 1260 |
| 1261 describe('error handling', () { |
| 1262 it('should return true or false depending on if an error exists on a form'
, |
| 1263 (Scope scope, TestBed _) { |
| 1264 |
| 1265 _.compile('<input type="text" ng-model="input" name="input" probe="i" />
'); |
| 1266 scope.apply(); |
| 1267 |
| 1268 Probe p = scope.context['i']; |
| 1269 NgModel model = p.directive(NgModel); |
| 1270 |
| 1271 expect(model.hasErrorState('big-failure')).toBe(false); |
| 1272 |
| 1273 model.addError("big-failure"); |
| 1274 |
| 1275 expect(model.hasErrorState('big-failure')).toBe(true); |
| 1276 |
| 1277 model.removeError("big-failure"); |
| 1278 |
| 1279 expect(model.hasErrorState('big-failure')).toBe(false); |
| 1280 }); |
970 }); | 1281 }); |
971 | 1282 |
972 describe('text-like events', () { | 1283 describe('text-like events', () { |
973 it('should update the binding on the "input" event', inject(() { | 1284 it('should update the binding on the "input" event', () { |
974 _.compile('<input type="text" ng-model="model" probe="p">'); | 1285 _.compile('<input type="text" ng-model="model" probe="p">'); |
975 Probe probe = _.rootScope.context['p']; | 1286 Probe probe = _.rootScope.context['p']; |
976 InputElement inputElement = probe.element; | 1287 InputElement inputElement = probe.element; |
977 | 1288 |
978 inputElement.value = 'waaaah'; | 1289 inputElement.value = 'waaaah'; |
979 | 1290 |
980 expect(_.rootScope.context['model']).not.toEqual('waaaah'); | 1291 expect(_.rootScope.context['model']).not.toEqual('waaaah'); |
981 | 1292 |
982 _.triggerEvent(inputElement, 'input'); | 1293 _.triggerEvent(inputElement, 'input'); |
983 | 1294 |
984 expect(_.rootScope.context['model']).toEqual('waaaah'); | 1295 expect(_.rootScope.context['model']).toEqual('waaaah'); |
985 })); | 1296 }); |
986 }); | 1297 }); |
987 | 1298 |
988 describe('error messages', () { | 1299 describe('error messages', () { |
989 it('should produce a useful error for bad ng-model expressions', () { | 1300 it('should produce a useful error for bad ng-model expressions', () { |
990 expect(async(() { | 1301 expect(async(() { |
991 _.compile('<div no-love><textarea ng-model=ctrl.love probe="loveProbe"
></textarea></div'); | 1302 _.compile('<div no-love><textarea ng-model=ctrl.love probe="loveProbe"
></textarea></div'); |
992 Probe probe = _.rootScope.context['loveProbe']; | 1303 Probe probe = _.rootScope.context['loveProbe']; |
993 TextAreaElement inputElement = probe.element; | 1304 TextAreaElement inputElement = probe.element; |
994 | 1305 |
995 inputElement.value = 'xzy'; | 1306 inputElement.value = 'xzy'; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1036 _.triggerEvent(input, 'blur'); | 1347 _.triggerEvent(input, 'blur'); |
1037 | 1348 |
1038 expect(model.touched).toBe(true); | 1349 expect(model.touched).toBe(true); |
1039 expect(model.untouched).toBe(false); | 1350 expect(model.untouched).toBe(false); |
1040 | 1351 |
1041 model.reset(); | 1352 model.reset(); |
1042 | 1353 |
1043 expect(model.touched).toBe(false); | 1354 expect(model.touched).toBe(false); |
1044 expect(model.untouched).toBe(true); | 1355 expect(model.untouched).toBe(true); |
1045 }); | 1356 }); |
| 1357 |
| 1358 describe('validators', () { |
| 1359 it('should display the valid and invalid CSS classes on the element for ea
ch validation', |
| 1360 (TestBed _, Scope scope) { |
| 1361 |
| 1362 var input = _.compile('<input type="email" ng-model="myModel" />'); |
| 1363 |
| 1364 scope.apply(() { |
| 1365 scope.context['myModel'] = 'value'; |
| 1366 }); |
| 1367 |
| 1368 expect(input).toHaveClass('ng-email-invalid'); |
| 1369 expect(input).not.toHaveClass('ng-email-valid'); |
| 1370 |
| 1371 scope.apply(() { |
| 1372 scope.context['myModel'] = 'value@email.com'; |
| 1373 }); |
| 1374 |
| 1375 expect(input).toHaveClass('ng-email-valid'); |
| 1376 expect(input).not.toHaveClass('ng-email-invalid'); |
| 1377 }); |
| 1378 |
| 1379 it('should display the valid and invalid CSS classes on the element for cu
stom validations', |
| 1380 (TestBed _, Scope scope) { |
| 1381 |
| 1382 var input = _.compile('<input type="text" ng-model="myModel" custom-inpu
t-validation />'); |
| 1383 |
| 1384 scope.apply(); |
| 1385 |
| 1386 expect(input).toHaveClass('custom-invalid'); |
| 1387 expect(input).not.toHaveClass('custom-valid'); |
| 1388 |
| 1389 scope.apply(() { |
| 1390 scope.context['myModel'] = 'yes'; |
| 1391 }); |
| 1392 |
| 1393 expect(input).toHaveClass('custom-valid'); |
| 1394 expect(input).not.toHaveClass('custom-invalid'); |
| 1395 }); |
| 1396 |
| 1397 it('should only validate twice during compilation and once upon scope dige
st', |
| 1398 (TestBed _, Scope scope) { |
| 1399 |
| 1400 scope.context['required'] = true; |
| 1401 _.compile('<input type="text" ' |
| 1402 'ng-model="model" ' |
| 1403 'ng-required="required" ' |
| 1404 'ng-pattern="pattern" ' |
| 1405 'counting-validator ' |
| 1406 'probe="i">'); |
| 1407 |
| 1408 scope.context['pattern'] = '^[aeiou]+\$'; |
| 1409 scope.context['required'] = true; |
| 1410 |
| 1411 scope.apply(); |
| 1412 |
| 1413 var model = scope.context['i'].directive(NgModel); |
| 1414 var counter = model.validators.firstWhere((validator) => validator.name
== 'counting'); |
| 1415 |
| 1416 // TODO(#881): There is a bug in ngModel where the validators are valida
ted too often. |
| 1417 // Should be 2. One for ngModel and one for all the other ones |
| 1418 // Currently, this count is 2 on Chrome and 3 on Firefox. |
| 1419 expect(counter.count == 2 || counter.count == 3).toBe(true); |
| 1420 expect(model.invalid).toBe(true); |
| 1421 |
| 1422 counter.count = 0; |
| 1423 scope.context['pattern'] = ''; |
| 1424 scope.context['required'] = false; |
| 1425 scope.apply(); |
| 1426 |
| 1427 expect(counter.count).toBe(1); |
| 1428 }); |
| 1429 |
| 1430 it('should only validate twice regardless of attribute order', (TestBed _,
Scope scope) { |
| 1431 scope.context['required'] = true; |
| 1432 _.compile('<input type="text" ' |
| 1433 'ng-required="required" ' |
| 1434 'ng-pattern="pattern" ' |
| 1435 'counting-validator ' |
| 1436 'ng-model="model" ' |
| 1437 'probe="i">'); |
| 1438 |
| 1439 scope.context['pattern'] = '^[aeiou]+\$'; |
| 1440 scope.context['required'] = true; |
| 1441 |
| 1442 scope.apply(); |
| 1443 |
| 1444 var model = scope.context['i'].directive(NgModel); |
| 1445 |
| 1446 var counter = model.validators.firstWhere((validator) => validator.name
== 'counting'); |
| 1447 |
| 1448 // TODO(#881): There is a bug in ngModel where the validators are valida
ted too often. |
| 1449 // Should be 2. One for ngModel and one for all the other ones |
| 1450 // Currently, this count is 3 on Chrome and 1 on Firefox. |
| 1451 expect(counter.count == 2 || counter.count == 3).toBe(true); |
| 1452 }); |
| 1453 }); |
| 1454 |
| 1455 describe('converters', () { |
| 1456 it('should parse the model value according to the given parser', (Scope sc
ope) { |
| 1457 _.compile('<input type="text" ng-model="model" probe="i">'); |
| 1458 scope.apply(); |
| 1459 |
| 1460 var probe = scope.context['i']; |
| 1461 var input = probe.element; |
| 1462 var model = probe.directive(NgModel); |
| 1463 model.converter = new LowercaseValueParser(); |
| 1464 |
| 1465 input.value = 'HELLO'; |
| 1466 _.triggerEvent(input, 'change'); |
| 1467 _.rootScope.apply(); |
| 1468 |
| 1469 expect(model.viewValue).toEqual('HELLO'); |
| 1470 expect(model.modelValue).toEqual('hello'); |
| 1471 }); |
| 1472 |
| 1473 it('should format the model value according to the given formatter', (Scop
e scope) { |
| 1474 _.compile('<input type="text" ng-model="model" probe="i">'); |
| 1475 scope.apply(); |
| 1476 |
| 1477 var probe = scope.context['i']; |
| 1478 var input = probe.element; |
| 1479 var model = probe.directive(NgModel); |
| 1480 model.converter = new UppercaseValueFormatter(); |
| 1481 |
| 1482 scope.apply(() { |
| 1483 scope.context['model'] = 'greetings'; |
| 1484 }); |
| 1485 |
| 1486 expect(model.viewValue).toEqual('GREETINGS'); |
| 1487 expect(model.modelValue).toEqual('greetings'); |
| 1488 }); |
| 1489 |
| 1490 it('should retain the current input value if the parser fails', (Scope sco
pe) { |
| 1491 _.compile('<form name="myForm">' + |
| 1492 ' <input type="text" ng-model="model1" name="myModel1" probe="
i">' + |
| 1493 ' <input type="text" ng-model="model2" name="myModel2" probe="
j">' + |
| 1494 '</form>'); |
| 1495 scope.apply(); |
| 1496 |
| 1497 var probe1 = scope.context['i']; |
| 1498 var input1 = probe1.element; |
| 1499 var model1 = probe1.directive(NgModel); |
| 1500 |
| 1501 var probe2 = scope.context['j']; |
| 1502 var input2 = probe2.element; |
| 1503 var model2 = probe2.directive(NgModel); |
| 1504 |
| 1505 model1.converter = new FailedValueParser(); |
| 1506 |
| 1507 input1.value = '123'; |
| 1508 _.triggerEvent(input1, 'change'); |
| 1509 _.rootScope.apply(); |
| 1510 |
| 1511 expect(model1.viewValue).toEqual('123'); |
| 1512 expect(input1.value).toEqual('123'); |
| 1513 expect(model1.modelValue).toEqual(null); |
| 1514 |
| 1515 expect(model2.viewValue).toEqual(null); |
| 1516 expect(input2.value).toEqual(''); |
| 1517 expect(model2.modelValue).toEqual(null); |
| 1518 }); |
| 1519 |
| 1520 it('should reformat the viewValue when the formatter is changed', (Scope s
cope) { |
| 1521 _.compile('<input type="text" ng-model="model" probe="i">'); |
| 1522 scope.apply(); |
| 1523 |
| 1524 var probe = scope.context['i']; |
| 1525 var input = probe.element; |
| 1526 var model = probe.directive(NgModel); |
| 1527 model.converter = new LowercaseValueParser(); |
| 1528 |
| 1529 input.value = 'HI THERE'; |
| 1530 _.triggerEvent(input, 'change'); |
| 1531 _.rootScope.apply(); |
| 1532 |
| 1533 expect(model.viewValue).toEqual('HI THERE'); |
| 1534 expect(model.modelValue).toEqual('hi there'); |
| 1535 |
| 1536 model.converter = new VowelValueParser(); |
| 1537 |
| 1538 expect(model.viewValue).toEqual('iee'); |
| 1539 expect(model.modelValue).toEqual('hi there'); |
| 1540 }); |
| 1541 }); |
1046 }); | 1542 }); |
1047 } | 1543 } |
1048 | 1544 |
1049 @NgController( | 1545 @Controller( |
1050 selector: '[no-love]', | 1546 selector: '[no-love]', |
1051 publishAs: 'ctrl') | 1547 publishAs: 'ctrl') |
1052 class ControllerWithNoLove { | 1548 class ControllerWithNoLove { |
1053 var apathy = null; | 1549 var apathy = null; |
1054 } | 1550 } |
| 1551 |
| 1552 class LowercaseValueParser implements NgModelConverter { |
| 1553 final name = 'lowercase'; |
| 1554 format(value) => value; |
| 1555 parse(value) { |
| 1556 return value != null ? value.toLowerCase() : null; |
| 1557 } |
| 1558 } |
| 1559 |
| 1560 class UppercaseValueFormatter implements NgModelConverter { |
| 1561 final name = 'uppercase'; |
| 1562 parse(value) => value; |
| 1563 format(value) { |
| 1564 return value != null ? value.toUpperCase() : null; |
| 1565 } |
| 1566 } |
| 1567 |
| 1568 class FailedValueParser implements NgModelConverter { |
| 1569 final name = 'failed'; |
| 1570 format(value) => value; |
| 1571 parse(value) { |
| 1572 throw new Exception(); |
| 1573 } |
| 1574 } |
| 1575 |
| 1576 class VowelValueParser implements NgModelConverter { |
| 1577 final name = 'vowel'; |
| 1578 parse(value) => value; |
| 1579 format(value) { |
| 1580 if(value != null) { |
| 1581 var exp = new RegExp("[^aeiouAEIOU]"); |
| 1582 value = value.replaceAll(exp, ""); |
| 1583 } |
| 1584 return value; |
| 1585 } |
| 1586 } |
| 1587 |
| 1588 @Decorator( |
| 1589 selector: '[custom-input-validation]') |
| 1590 class MyCustomInputValidator extends NgValidator { |
| 1591 MyCustomInputValidator(NgModel ngModel) { |
| 1592 ngModel.addValidator(this); |
| 1593 } |
| 1594 |
| 1595 final String name = 'custom'; |
| 1596 |
| 1597 bool isValid(name) { |
| 1598 return name != null && name == 'yes'; |
| 1599 } |
| 1600 } |
| 1601 |
| 1602 @Decorator( |
| 1603 selector: '[counting-validator]') |
| 1604 class CountingValidator extends NgValidator { |
| 1605 |
| 1606 final String name = 'counting'; |
| 1607 int count = 0; |
| 1608 |
| 1609 CountingValidator(NgModel ngModel) { |
| 1610 ngModel.addValidator(this); |
| 1611 } |
| 1612 |
| 1613 bool isValid(String modelValue) { |
| 1614 count++; |
| 1615 return true; |
| 1616 } |
| 1617 } |
OLD | NEW |