| 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 |