| 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 | |
| 36 void main() { | 6 void main() { |
| 37 describe('ng-model', () { | 7 describe('ng-model', () { |
| 38 TestBed _; | 8 TestBed _; |
| 39 | 9 |
| 40 beforeEachModule((Module module) { | 10 beforeEach(module((Module module) { |
| 41 module | 11 module..type(ControllerWithNoLove); |
| 42 ..type(ControllerWithNoLove) | 12 })); |
| 43 ..type(MyCustomInputValidator) | |
| 44 ..type(CountingValidator); | |
| 45 }); | |
| 46 | 13 |
| 47 beforeEach((TestBed tb) => _ = tb); | 14 beforeEach(inject((TestBed tb) => _ = tb)); |
| 48 | 15 |
| 49 describe('type="text" like', () { | 16 describe('type="text" like', () { |
| 50 it('should update input value from model', () { | 17 it('should update input value from model', inject(() { |
| 51 _.compile('<input type="text" ng-model="model">'); | 18 _.compile('<input type="text" ng-model="model">'); |
| 52 _.rootScope.apply(); | 19 _.rootScope.apply(); |
| 53 | 20 |
| 54 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 21 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 55 | 22 |
| 56 _.rootScope.apply('model = "misko"'); | 23 _.rootScope.apply('model = "misko"'); |
| 57 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 24 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
| 58 }); | 25 })); |
| 59 | 26 |
| 60 it('should render null as the empty string', () { | 27 it('should render null as the empty string', inject(() { |
| 61 _.compile('<input type="text" ng-model="model">'); | 28 _.compile('<input type="text" ng-model="model">'); |
| 62 _.rootScope.apply(); | 29 _.rootScope.apply(); |
| 63 | 30 |
| 64 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 31 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 65 | 32 |
| 66 _.rootScope.apply('model = null'); | 33 _.rootScope.apply('model = null'); |
| 67 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 34 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 68 }); | 35 })); |
| 69 | 36 |
| 70 it('should update model from the input value', () { | 37 it('should update model from the input value', inject(() { |
| 71 _.compile('<input type="text" ng-model="model" probe="p">'); | 38 _.compile('<input type="text" ng-model="model" probe="p">'); |
| 72 Probe probe = _.rootScope.context['p']; | 39 Probe probe = _.rootScope.context['p']; |
| 73 var ngModel = probe.directive(NgModel); | 40 var ngModel = probe.directive(NgModel); |
| 74 InputElement inputElement = probe.element; | 41 InputElement inputElement = probe.element; |
| 75 | 42 |
| 76 inputElement.value = 'abc'; | 43 inputElement.value = 'abc'; |
| 77 _.triggerEvent(inputElement, 'change'); | 44 _.triggerEvent(inputElement, 'change'); |
| 78 expect(_.rootScope.context['model']).toEqual('abc'); | 45 expect(_.rootScope.context['model']).toEqual('abc'); |
| 79 | 46 |
| 80 inputElement.value = 'def'; | 47 inputElement.value = 'def'; |
| 81 var input = probe.directive(InputTextLike); | 48 var input = probe.directive(InputTextLikeDirective); |
| 82 input.processValue(); | 49 input.processValue(); |
| 83 expect(_.rootScope.context['model']).toEqual('def'); | 50 expect(_.rootScope.context['model']).toEqual('def'); |
| 84 }); | 51 })); |
| 85 | 52 |
| 86 it('should write to input only if the value is different', | 53 it('should update model from the input value for type=number', inject(() { |
| 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', () { | |
| 144 _.compile('<input type="number" ng-model="model" probe="p">'); | 54 _.compile('<input type="number" ng-model="model" probe="p">'); |
| 145 Probe probe = _.rootScope.context['p']; | 55 Probe probe = _.rootScope.context['p']; |
| 146 var ngModel = probe.directive(NgModel); | 56 var ngModel = probe.directive(NgModel); |
| 147 InputElement inputElement = probe.element; | 57 InputElement inputElement = probe.element; |
| 148 | 58 |
| 149 inputElement.value = '12'; | 59 inputElement.value = '12'; |
| 150 _.triggerEvent(inputElement, 'change'); | 60 _.triggerEvent(inputElement, 'change'); |
| 151 expect(_.rootScope.context['model']).toEqual(12); | 61 expect(_.rootScope.context['model']).toEqual(12); |
| 152 | 62 |
| 153 inputElement.value = '14'; | 63 inputElement.value = '14'; |
| 154 var input = probe.directive(InputNumberLike); | 64 var input = probe.directive(InputNumberLikeDirective); |
| 155 input.processValue(); | 65 input.processValue(); |
| 156 expect(_.rootScope.context['model']).toEqual(14); | 66 expect(_.rootScope.context['model']).toEqual(14); |
| 157 }); | 67 })); |
| 158 | 68 |
| 159 it('should update input type=number to blank when model is null', () { | 69 it('should update input type=number to blank when model is null', inject((
) { |
| 160 _.compile('<input type="number" ng-model="model" probe="p">'); | 70 _.compile('<input type="number" ng-model="model" probe="p">'); |
| 161 Probe probe = _.rootScope.context['p']; | 71 Probe probe = _.rootScope.context['p']; |
| 162 var ngModel = probe.directive(NgModel); | 72 var ngModel = probe.directive(NgModel); |
| 163 InputElement inputElement = probe.element; | 73 InputElement inputElement = probe.element; |
| 164 | 74 |
| 165 inputElement.value = '12'; | 75 inputElement.value = '12'; |
| 166 _.triggerEvent(inputElement, 'change'); | 76 _.triggerEvent(inputElement, 'change'); |
| 167 expect(_.rootScope.context['model']).toEqual(12); | 77 expect(_.rootScope.context['model']).toEqual(12); |
| 168 | 78 |
| 169 _.rootScope.context['model'] = null; | 79 _.rootScope.context['model'] = null; |
| 170 _.rootScope.apply(); | 80 _.rootScope.apply(); |
| 171 expect(inputElement.value).toEqual(''); | 81 expect(inputElement.value).toEqual(''); |
| 172 }); | 82 })); |
| 173 | 83 |
| 174 it('should be invalid when the input value results in a NaN value', () { | 84 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { |
| 175 _.compile('<input type="number" ng-model="model" probe="p">'); | 85 var scope = _.rootScope; |
| 176 Probe probe = _.rootScope.context['p']; | 86 var element = new dom.InputElement(); |
| 177 var ngModel = probe.directive(NgModel); | 87 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
| 178 InputElement inputElement = probe.element; | 88 nodeAttrs['ng-model'] = 'model'; |
| 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); |
| 179 | 92 |
| 180 inputElement.value = 'aa'; | 93 element |
| 181 _.triggerEvent(inputElement, 'change'); | 94 ..value = 'abc' |
| 182 expect(_.rootScope.context['model'].isNaN).toBe(true); | 95 ..selectionStart = 1 |
| 183 expect(ngModel.valid).toBe(false); | 96 ..selectionEnd = 2; |
| 184 }); | |
| 185 | 97 |
| 186 it('should leave input unchanged when text does not represent a valid numb
er', (Injector i) { | 98 model.render('abc'); |
| 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) { |
| 187 var modelFieldName = 'modelForNumFromInvalid1'; | 127 var modelFieldName = 'modelForNumFromInvalid1'; |
| 188 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); | 128 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); |
| 189 dom.querySelector('body').append(element); | 129 dom.querySelector('body').append(element); |
| 190 | 130 |
| 191 if (!simulateTypingTextWithConfirmation(element, '1')) return; // skip t
est. | |
| 192 element.value = ''; // reset input | |
| 193 | |
| 194 // This test will progressively enter the text '1e1' | 131 // This test will progressively enter the text '1e1' |
| 195 // '1' is a valid number. | 132 // '1' is a valid number. |
| 196 // '1e' is not a valid number. | 133 // '1e' is not a valid number. |
| 197 // '1e1' is again a valid number (with an exponent) | 134 // '1e1' is again a valid number (with an exponent) |
| 198 | 135 |
| 199 simulateTypingText(element, '1'); | 136 simulateTypingText(element, '1'); |
| 200 _.triggerEvent(element, 'change'); | 137 _.triggerEvent(element, 'change'); |
| 201 expect(element.value).toEqual('1'); | 138 expect(element.value).toEqual('1'); |
| 202 expect(_.rootScope.context[modelFieldName]).toEqual(1); | 139 expect(_.rootScope.context[modelFieldName]).toEqual(1); |
| 203 | 140 |
| 204 simulateTypingText(element, 'e'); | 141 simulateTypingText(element, 'e'); |
| 205 // Because the text is not a valid number, the element value is empty. | 142 // Because the text is not a valid number, the element value is empty. |
| 206 expect(element.value).toEqual(''); | 143 expect(element.value).toEqual(''); |
| 207 // When the input is invalid, the model is [double.NAN]: | 144 // When the input is invalid, the model is [double.NAN]: |
| 208 _.triggerEvent(element, 'change'); | 145 _.triggerEvent(element, 'change'); |
| 209 expect(_.rootScope.context[modelFieldName].isNaN).toBeTruthy(); | 146 expect(_.rootScope.context[modelFieldName].isNaN).toBeTruthy(); |
| 210 | 147 |
| 211 simulateTypingText(element, '1'); | 148 simulateTypingText(element, '1'); |
| 212 _.triggerEvent(element, 'change'); | 149 _.triggerEvent(element, 'change'); |
| 213 expect(element.value).toEqual('1e1'); | 150 expect(element.value).toEqual('1e1'); |
| 214 expect(_.rootScope.context[modelFieldName]).toEqual(10); | 151 expect(_.rootScope.context[modelFieldName]).toEqual(10); |
| 215 }); | 152 })); |
| 216 | 153 |
| 217 it('should not reformat user input to equivalent numeric representation',
(Injector i) { | 154 it('should not reformat user input to equivalent numeric representation',
inject((Injector i) { |
| 218 var modelFieldName = 'modelForNumFromInvalid2'; | 155 var modelFieldName = 'modelForNumFromInvalid2'; |
| 219 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); | 156 var element = _.compile('<input type="number" ng-model="$modelFieldName"
>'); |
| 220 dom.querySelector('body').append(element); | 157 dom.querySelector('body').append(element); |
| 221 | 158 |
| 222 if (!simulateTypingTextWithConfirmation(element, '1')) return; // skip t
est. | |
| 223 element.value = ''; // reset input | |
| 224 | |
| 225 simulateTypingText(element, '1e-1'); | 159 simulateTypingText(element, '1e-1'); |
| 226 expect(element.value).toEqual('1e-1'); | 160 expect(element.value).toEqual('1e-1'); |
| 227 expect(_.rootScope.context[modelFieldName]).toEqual(0.1); | 161 expect(_.rootScope.context[modelFieldName]).toEqual(0.1); |
| 228 }); | 162 })); |
| 229 | 163 |
| 230 it('should update input value from model', () { | 164 it('should update input value from model', inject(() { |
| 231 _.compile('<input type="number" ng-model="model">'); | 165 _.compile('<input type="number" ng-model="model">'); |
| 232 _.rootScope.apply(); | 166 _.rootScope.apply(); |
| 233 | 167 |
| 234 _.rootScope.apply('model = 42'); | 168 _.rootScope.apply('model = 42'); |
| 235 expect((_.rootElement as dom.InputElement).value).toEqual('42'); | 169 expect((_.rootElement as dom.InputElement).value).toEqual('42'); |
| 236 }); | 170 })); |
| 237 | 171 |
| 238 it('should update input value from model for range inputs', () { | 172 it('should update input value from model for range inputs', inject(() { |
| 239 _.compile('<input type="range" ng-model="model">'); | 173 _.compile('<input type="range" ng-model="model">'); |
| 240 _.rootScope.apply(); | 174 _.rootScope.apply(); |
| 241 | 175 |
| 242 _.rootScope.apply('model = 42'); | 176 _.rootScope.apply('model = 42'); |
| 243 expect((_.rootElement as dom.InputElement).value).toEqual('42'); | 177 expect((_.rootElement as dom.InputElement).value).toEqual('42'); |
| 244 }); | 178 })); |
| 245 | 179 |
| 246 it('should update model from the input value', () { | 180 it('should update model from the input value', inject(() { |
| 247 _.compile('<input type="number" ng-model="model" probe="p">'); | 181 _.compile('<input type="number" ng-model="model" probe="p">'); |
| 248 Probe probe = _.rootScope.context['p']; | 182 Probe probe = _.rootScope.context['p']; |
| 249 var ngModel = probe.directive(NgModel); | 183 var ngModel = probe.directive(NgModel); |
| 250 InputElement inputElement = probe.element; | 184 InputElement inputElement = probe.element; |
| 251 | 185 |
| 252 inputElement.value = '42'; | 186 inputElement.value = '42'; |
| 253 _.triggerEvent(inputElement, 'change'); | 187 _.triggerEvent(inputElement, 'change'); |
| 254 expect(_.rootScope.context['model']).toEqual(42); | 188 expect(_.rootScope.context['model']).toEqual(42); |
| 255 | 189 |
| 256 inputElement.value = '43'; | 190 inputElement.value = '43'; |
| 257 var input = probe.directive(InputNumberLike); | 191 var input = probe.directive(InputNumberLikeDirective); |
| 258 input.processValue(); | 192 input.processValue(); |
| 259 expect(_.rootScope.context['model']).toEqual(43); | 193 expect(_.rootScope.context['model']).toEqual(43); |
| 260 }); | 194 })); |
| 261 | 195 |
| 262 it('should update model to NaN from a blank input value', () { | 196 it('should update model to NaN from a blank input value', inject(() { |
| 263 _.compile('<input type="number" ng-model="model" probe="p">'); | 197 _.compile('<input type="number" ng-model="model" probe="p">'); |
| 264 Probe probe = _.rootScope.context['p']; | 198 Probe probe = _.rootScope.context['p']; |
| 265 var ngModel = probe.directive(NgModel); | 199 var ngModel = probe.directive(NgModel); |
| 266 InputElement inputElement = probe.element; | 200 InputElement inputElement = probe.element; |
| 267 | 201 |
| 268 inputElement.value = ''; | 202 inputElement.value = ''; |
| 269 _.triggerEvent(inputElement, 'change'); | 203 _.triggerEvent(inputElement, 'change'); |
| 270 expect(_.rootScope.context['model'].isNaN).toBeTruthy(); | 204 expect(_.rootScope.context['model'].isNaN).toBeTruthy(); |
| 271 }); | 205 })); |
| 272 | 206 |
| 273 it('should update model from the input value for range inputs', () { | 207 it('should update model from the input value for range inputs', inject(()
{ |
| 274 _.compile('<input type="range" ng-model="model" probe="p">'); | 208 _.compile('<input type="range" ng-model="model" probe="p">'); |
| 275 Probe probe = _.rootScope.context['p']; | 209 Probe probe = _.rootScope.context['p']; |
| 276 var ngModel = probe.directive(NgModel); | 210 var ngModel = probe.directive(NgModel); |
| 277 InputElement inputElement = probe.element; | 211 InputElement inputElement = probe.element; |
| 278 | 212 |
| 279 inputElement.value = '42'; | 213 inputElement.value = '42'; |
| 280 _.triggerEvent(inputElement, 'change'); | 214 _.triggerEvent(inputElement, 'change'); |
| 281 expect(_.rootScope.context['model']).toEqual(42); | 215 expect(_.rootScope.context['model']).toEqual(42); |
| 282 | 216 |
| 283 inputElement.value = '43'; | 217 inputElement.value = '43'; |
| 284 var input = probe.directive(InputNumberLike); | 218 var input = probe.directive(InputNumberLikeDirective); |
| 285 input.processValue(); | 219 input.processValue(); |
| 286 expect(_.rootScope.context['model']).toEqual(43); | 220 expect(_.rootScope.context['model']).toEqual(43); |
| 287 }); | 221 })); |
| 288 | 222 |
| 289 it('should update model to a native default value from a blank range input
value', () { | 223 it('should update model to a native default value from a blank range input
value', inject(() { |
| 290 _.compile('<input type="range" ng-model="model" probe="p">'); | 224 _.compile('<input type="range" ng-model="model" probe="p">'); |
| 291 Probe probe = _.rootScope.context['p']; | 225 Probe probe = _.rootScope.context['p']; |
| 292 var ngModel = probe.directive(NgModel); | 226 var ngModel = probe.directive(NgModel); |
| 293 InputElement inputElement = probe.element; | 227 InputElement inputElement = probe.element; |
| 294 | 228 |
| 295 inputElement.value = ''; | 229 inputElement.value = ''; |
| 296 _.triggerEvent(inputElement, 'change'); | 230 _.triggerEvent(inputElement, 'change'); |
| 297 expect(_.rootScope.context['model']).toBeDefined(); | 231 expect(_.rootScope.context['model']).toBeDefined(); |
| 298 }); | 232 })); |
| 299 | 233 |
| 300 it('should render null as blank', () { | 234 it('should render null as blank', inject(() { |
| 301 _.compile('<input type="number" ng-model="model">'); | 235 _.compile('<input type="number" ng-model="model">'); |
| 302 _.rootScope.apply(); | 236 _.rootScope.apply(); |
| 303 | 237 |
| 304 _.rootScope.apply('model = null'); | 238 _.rootScope.apply('model = null'); |
| 305 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 239 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 306 }); | 240 })); |
| 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 }); | |
| 323 | 241 |
| 324 }); | 242 }); |
| 325 | 243 |
| 326 describe('type="password"', () { | 244 describe('type="password"', () { |
| 327 it('should update input value from model', () { | 245 it('should update input value from model', inject(() { |
| 328 _.compile('<input type="password" ng-model="model">'); | 246 _.compile('<input type="password" ng-model="model">'); |
| 329 _.rootScope.apply(); | 247 _.rootScope.apply(); |
| 330 | 248 |
| 331 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 249 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 332 | 250 |
| 333 _.rootScope.apply('model = "misko"'); | 251 _.rootScope.apply('model = "misko"'); |
| 334 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 252 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
| 335 }); | 253 })); |
| 336 | 254 |
| 337 it('should render null as the empty string', () { | 255 it('should render null as the empty string', inject(() { |
| 338 _.compile('<input type="password" ng-model="model">'); | 256 _.compile('<input type="password" ng-model="model">'); |
| 339 _.rootScope.apply(); | 257 _.rootScope.apply(); |
| 340 | 258 |
| 341 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 259 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 342 | 260 |
| 343 _.rootScope.apply('model = null'); | 261 _.rootScope.apply('model = null'); |
| 344 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 262 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 345 }); | 263 })); |
| 346 | 264 |
| 347 it('should update model from the input value', () { | 265 it('should update model from the input value', inject(() { |
| 348 _.compile('<input type="password" ng-model="model" probe="p">'); | 266 _.compile('<input type="password" ng-model="model" probe="p">'); |
| 349 Probe probe = _.rootScope.context['p']; | 267 Probe probe = _.rootScope.context['p']; |
| 350 var ngModel = probe.directive(NgModel); | 268 var ngModel = probe.directive(NgModel); |
| 351 InputElement inputElement = probe.element; | 269 InputElement inputElement = probe.element; |
| 352 | 270 |
| 353 inputElement.value = 'abc'; | 271 inputElement.value = 'abc'; |
| 354 _.triggerEvent(inputElement, 'change'); | 272 _.triggerEvent(inputElement, 'change'); |
| 355 expect(_.rootScope.context['model']).toEqual('abc'); | 273 expect(_.rootScope.context['model']).toEqual('abc'); |
| 356 | 274 |
| 357 inputElement.value = 'def'; | 275 inputElement.value = 'def'; |
| 358 var input = probe.directive(InputTextLike); | 276 var input = probe.directive(InputTextLikeDirective); |
| 359 input.processValue(); | 277 input.processValue(); |
| 360 expect(_.rootScope.context['model']).toEqual('def'); | 278 expect(_.rootScope.context['model']).toEqual('def'); |
| 361 | 279 |
| 362 }); | 280 })); |
| 363 | 281 |
| 364 it('should write to input only if value is different', | 282 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { |
| 365 (Injector i, Animate animate) { | |
| 366 | |
| 367 var scope = _.rootScope; | 283 var scope = _.rootScope; |
| 368 var element = new dom.InputElement(); | 284 var element = new dom.InputElement(); |
| 369 var ngElement = new NgElement(element, scope, animate); | |
| 370 | |
| 371 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 285 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
| 372 nodeAttrs['ng-model'] = 'model'; | 286 nodeAttrs['ng-model'] = 'model'; |
| 373 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), | 287 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); |
| 374 nodeAttrs, new Animate()); | |
| 375 dom.querySelector('body').append(element); | 288 dom.querySelector('body').append(element); |
| 376 var input = new InputTextLike(element, model, scope); | 289 var input = new InputTextLikeDirective(element, model, scope); |
| 377 | 290 |
| 378 element | 291 element |
| 379 ..value = 'abc' | 292 ..value = 'abc' |
| 380 ..selectionStart = 1 | 293 ..selectionStart = 1 |
| 381 ..selectionEnd = 2; | 294 ..selectionEnd = 2; |
| 382 | 295 |
| 383 scope.apply(() { | 296 model.render('abc'); |
| 384 scope.context['model'] = 'abc'; | |
| 385 }); | |
| 386 | 297 |
| 387 expect(element.value).toEqual('abc'); | 298 expect(element.value).toEqual('abc'); |
| 388 expect(element.selectionStart).toEqual(1); | 299 expect(element.selectionStart).toEqual(1); |
| 389 expect(element.selectionEnd).toEqual(2); | 300 expect(element.selectionEnd).toEqual(2); |
| 390 | 301 |
| 391 scope.apply(() { | 302 model.render('xyz'); |
| 392 scope.context['model'] = 'xyz'; | |
| 393 }); | |
| 394 | 303 |
| 395 expect(element.value).toEqual('xyz'); | 304 expect(element.value).toEqual('xyz'); |
| 396 expect(element.selectionStart).toEqual(3); | 305 expect(element.selectionStart).toEqual(3); |
| 397 expect(element.selectionEnd).toEqual(3); | 306 expect(element.selectionEnd).toEqual(3); |
| 398 }); | 307 })); |
| 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 }); | |
| 415 }); | 308 }); |
| 416 | 309 |
| 417 describe('type="search"', () { | 310 describe('type="search"', () { |
| 418 it('should update input value from model', () { | 311 it('should update input value from model', inject(() { |
| 419 _.compile('<input type="search" ng-model="model">'); | 312 _.compile('<input type="search" ng-model="model">'); |
| 420 _.rootScope.apply(); | 313 _.rootScope.apply(); |
| 421 | 314 |
| 422 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 315 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 423 | 316 |
| 424 _.rootScope.apply('model = "misko"'); | 317 _.rootScope.apply('model = "misko"'); |
| 425 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 318 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
| 426 }); | 319 })); |
| 427 | 320 |
| 428 it('should render null as the empty string', () { | 321 it('should render null as the empty string', inject(() { |
| 429 _.compile('<input type="search" ng-model="model">'); | 322 _.compile('<input type="search" ng-model="model">'); |
| 430 _.rootScope.apply(); | 323 _.rootScope.apply(); |
| 431 | 324 |
| 432 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 325 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 433 | 326 |
| 434 _.rootScope.apply('model = null'); | 327 _.rootScope.apply('model = null'); |
| 435 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 328 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 436 }); | 329 })); |
| 437 | 330 |
| 438 it('should update model from the input value', () { | 331 it('should update model from the input value', inject(() { |
| 439 _.compile('<input type="search" ng-model="model" probe="p">'); | 332 _.compile('<input type="search" ng-model="model" probe="p">'); |
| 440 Probe probe = _.rootScope.context['p']; | 333 Probe probe = _.rootScope.context['p']; |
| 441 var ngModel = probe.directive(NgModel); | 334 var ngModel = probe.directive(NgModel); |
| 442 InputElement inputElement = probe.element; | 335 InputElement inputElement = probe.element; |
| 443 | 336 |
| 444 inputElement.value = 'abc'; | 337 inputElement.value = 'abc'; |
| 445 _.triggerEvent(inputElement, 'change'); | 338 _.triggerEvent(inputElement, 'change'); |
| 446 expect(_.rootScope.context['model']).toEqual('abc'); | 339 expect(_.rootScope.context['model']).toEqual('abc'); |
| 447 | 340 |
| 448 inputElement.value = 'def'; | 341 inputElement.value = 'def'; |
| 449 var input = probe.directive(InputTextLike); | 342 var input = probe.directive(InputTextLikeDirective); |
| 450 input.processValue(); | 343 input.processValue(); |
| 451 expect(_.rootScope.context['model']).toEqual('def'); | 344 expect(_.rootScope.context['model']).toEqual('def'); |
| 452 }); | 345 })); |
| 453 | 346 |
| 454 it('should write to input only if value is different', | 347 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { |
| 455 (Injector i, Animate animate) { | |
| 456 | |
| 457 var scope = _.rootScope; | 348 var scope = _.rootScope; |
| 458 var element = new dom.InputElement(); | 349 var element = new dom.InputElement(); |
| 459 var ngElement = new NgElement(element, scope, animate); | |
| 460 | |
| 461 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 350 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
| 462 nodeAttrs['ng-model'] = 'model'; | 351 nodeAttrs['ng-model'] = 'model'; |
| 463 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), | 352 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); |
| 464 nodeAttrs, new Animate()); | |
| 465 dom.querySelector('body').append(element); | 353 dom.querySelector('body').append(element); |
| 466 var input = new InputTextLike(element, model, scope); | 354 var input = new InputTextLikeDirective(element, model, scope); |
| 467 | 355 |
| 468 element | 356 element |
| 469 ..value = 'abc' | 357 ..value = 'abc' |
| 470 ..selectionStart = 1 | 358 ..selectionStart = 1 |
| 471 ..selectionEnd = 2; | 359 ..selectionEnd = 2; |
| 472 | 360 |
| 473 scope.apply(() { | 361 model.render('abc'); |
| 474 scope.context['model'] = 'abc'; | |
| 475 }); | |
| 476 | 362 |
| 477 expect(element.value).toEqual('abc'); | 363 expect(element.value).toEqual('abc'); |
| 478 // No update. selectionStart/End is unchanged. | 364 // No update. selectionStart/End is unchanged. |
| 479 expect(element.selectionStart).toEqual(1); | 365 expect(element.selectionStart).toEqual(1); |
| 480 expect(element.selectionEnd).toEqual(2); | 366 expect(element.selectionEnd).toEqual(2); |
| 481 | 367 |
| 482 scope.apply(() { | 368 model.render('xyz'); |
| 483 scope.context['model'] = 'xyz'; | |
| 484 }); | |
| 485 | 369 |
| 486 // Value updated. selectionStart/End changed. | 370 // Value updated. selectionStart/End changed. |
| 487 expect(element.value).toEqual('xyz'); | 371 expect(element.value).toEqual('xyz'); |
| 488 expect(element.selectionStart).toEqual(3); | 372 expect(element.selectionStart).toEqual(3); |
| 489 expect(element.selectionEnd).toEqual(3); | 373 expect(element.selectionEnd).toEqual(3); |
| 490 }); | 374 })); |
| 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 }); | |
| 507 }); | 375 }); |
| 508 | 376 |
| 509 describe('no type attribute', () { | 377 describe('no type attribute', () { |
| 510 it('should be set "text" as default value for "type" attribute', () { | 378 it('should be set "text" as default value for "type" attribute', inject(()
{ |
| 511 _.compile('<input ng-model="model">'); | 379 _.compile('<input ng-model="model">'); |
| 512 _.rootScope.apply(); | 380 _.rootScope.apply(); |
| 513 expect((_.rootElement as dom.InputElement).attributes['type']).toEqual('
text'); | 381 expect((_.rootElement as dom.InputElement).attributes['type']).toEqual('
text'); |
| 514 }); | 382 })); |
| 515 | 383 |
| 516 it('should update input value from model', () { | 384 it('should update input value from model', inject(() { |
| 517 _.compile('<input ng-model="model">'); | 385 _.compile('<input ng-model="model">'); |
| 518 _.rootScope.apply(); | 386 _.rootScope.apply(); |
| 519 | 387 |
| 520 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 388 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 521 | 389 |
| 522 _.rootScope.apply('model = "misko"'); | 390 _.rootScope.apply('model = "misko"'); |
| 523 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); | 391 expect((_.rootElement as dom.InputElement).value).toEqual('misko'); |
| 524 }); | 392 })); |
| 525 | 393 |
| 526 it('should render null as the empty string', () { | 394 it('should render null as the empty string', inject(() { |
| 527 _.compile('<input ng-model="model">'); | 395 _.compile('<input ng-model="model">'); |
| 528 _.rootScope.apply(); | 396 _.rootScope.apply(); |
| 529 | 397 |
| 530 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 398 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 531 | 399 |
| 532 _.rootScope.apply('model = null'); | 400 _.rootScope.apply('model = null'); |
| 533 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 401 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 534 }); | 402 })); |
| 535 | 403 |
| 536 it('should update model from the input value', () { | 404 it('should update model from the input value', inject(() { |
| 537 _.compile('<input ng-model="model" probe="p">'); | 405 _.compile('<input ng-model="model" probe="p">'); |
| 538 Probe probe = _.rootScope.context['p']; | 406 Probe probe = _.rootScope.context['p']; |
| 539 var ngModel = probe.directive(NgModel); | 407 var ngModel = probe.directive(NgModel); |
| 540 InputElement inputElement = probe.element; | 408 InputElement inputElement = probe.element; |
| 541 | 409 |
| 542 inputElement.value = 'abc'; | 410 inputElement.value = 'abc'; |
| 543 _.triggerEvent(inputElement, 'change'); | 411 _.triggerEvent(inputElement, 'change'); |
| 544 expect(_.rootScope.context['model']).toEqual('abc'); | 412 expect(_.rootScope.context['model']).toEqual('abc'); |
| 545 | 413 |
| 546 inputElement.value = 'def'; | 414 inputElement.value = 'def'; |
| 547 var input = probe.directive(InputTextLike); | 415 var input = probe.directive(InputTextLikeDirective); |
| 548 input.processValue(); | 416 input.processValue(); |
| 549 expect(_.rootScope.context['model']).toEqual('def'); | 417 expect(_.rootScope.context['model']).toEqual('def'); |
| 550 }); | 418 })); |
| 551 | 419 |
| 552 it('should write to input only if value is different', | 420 it('should write to input only if value is different', inject((Injector i,
AstParser parser) { |
| 553 (Injector i, Animate animate) { | |
| 554 | |
| 555 var scope = _.rootScope; | 421 var scope = _.rootScope; |
| 556 var element = new dom.InputElement(); | 422 var element = new dom.InputElement(); |
| 557 var ngElement = new NgElement(element, scope, animate); | |
| 558 | |
| 559 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 423 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
| 560 nodeAttrs['ng-model'] = 'model'; | 424 nodeAttrs['ng-model'] = 'model'; |
| 561 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), | 425 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); |
| 562 nodeAttrs, new Animate()); | |
| 563 dom.querySelector('body').append(element); | 426 dom.querySelector('body').append(element); |
| 564 var input = new InputTextLike(element, model, scope); | 427 var input = new InputTextLikeDirective(element, model, scope); |
| 565 | 428 |
| 566 element | 429 element |
| 567 ..value = 'abc' | 430 ..value = 'abc' |
| 568 ..selectionStart = 1 | 431 ..selectionStart = 1 |
| 569 ..selectionEnd = 2; | 432 ..selectionEnd = 2; |
| 570 | 433 |
| 571 scope.apply(() { | 434 model.render('abc'); |
| 572 scope.context['model'] = 'abc'; | |
| 573 }); | |
| 574 | 435 |
| 575 expect(element.value).toEqual('abc'); | 436 expect(element.value).toEqual('abc'); |
| 576 expect(element.selectionStart).toEqual(1); | 437 expect(element.selectionStart).toEqual(1); |
| 577 expect(element.selectionEnd).toEqual(2); | 438 expect(element.selectionEnd).toEqual(2); |
| 578 | 439 |
| 579 scope.apply(() { | 440 model.render('xyz'); |
| 580 scope.context['model'] = 'xyz'; | |
| 581 }); | |
| 582 | 441 |
| 583 expect(element.value).toEqual('xyz'); | 442 expect(element.value).toEqual('xyz'); |
| 584 expect(element.selectionStart).toEqual(3); | 443 expect(element.selectionStart).toEqual(3); |
| 585 expect(element.selectionEnd).toEqual(3); | 444 expect(element.selectionEnd).toEqual(3); |
| 586 }); | 445 })); |
| 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 }); | |
| 603 }); | 446 }); |
| 604 | 447 |
| 605 describe('type="checkbox"', () { | 448 describe('type="checkbox"', () { |
| 606 it('should update input value from model', (Scope scope) { | 449 it('should update input value from model', inject((Scope scope) { |
| 607 var element = _.compile('<input type="checkbox" ng-model="model">'); | 450 var element = _.compile('<input type="checkbox" ng-model="model">'); |
| 608 | 451 |
| 609 scope.apply(() { | 452 scope.apply(() { |
| 610 scope.context['model'] = true; | 453 scope.context['model'] = true; |
| 611 }); | 454 }); |
| 612 expect(element.checked).toBe(true); | 455 expect(element.checked).toBe(true); |
| 613 | 456 |
| 614 scope.apply(() { | 457 scope.apply(() { |
| 615 scope.context['model'] = false; | 458 scope.context['model'] = false; |
| 616 }); | 459 }); |
| 617 expect(element.checked).toBe(false); | 460 expect(element.checked).toBe(false); |
| 618 }); | 461 })); |
| 619 | 462 |
| 620 it('should render as dirty when checked', (Scope scope) { | 463 it('should render as dirty when checked', inject((Scope scope) { |
| 621 var element = _.compile('<input type="text" ng-model="my_model" probe="i
" />'); | 464 var element = _.compile('<input type="text" ng-model="my_model" probe="i
" />'); |
| 622 Probe probe = _.rootScope.context['i']; | 465 Probe probe = _.rootScope.context['i']; |
| 623 var model = probe.directive(NgModel); | 466 var model = probe.directive(NgModel); |
| 624 | 467 |
| 625 expect(model.pristine).toEqual(true); | 468 expect(model.pristine).toEqual(true); |
| 626 expect(model.dirty).toEqual(false); | 469 expect(model.dirty).toEqual(false); |
| 627 | 470 |
| 628 _.triggerEvent(element, 'change'); | 471 _.triggerEvent(element, 'change'); |
| 629 | 472 |
| 630 expect(model.pristine).toEqual(false); | 473 expect(model.pristine).toEqual(false); |
| 631 expect(model.dirty).toEqual(true); | 474 expect(model.dirty).toEqual(true); |
| 632 }); | 475 })); |
| 633 | 476 |
| 634 it('should update input value from model using ng-true-value/false', (Scop
e scope) { | 477 |
| 478 it('should update input value from model using ng-true-value/false', injec
t((Scope scope) { |
| 635 var element = _.compile('<input type="checkbox" ng-model="model" ng-true
-value="1" ng-false-value="0">'); | 479 var element = _.compile('<input type="checkbox" ng-model="model" ng-true
-value="1" ng-false-value="0">'); |
| 636 | 480 |
| 637 scope.apply(() { | 481 scope.apply(() { |
| 638 scope.context['model'] = 1; | 482 scope.context['model'] = 1; |
| 639 }); | 483 }); |
| 640 expect(element.checked).toBe(true); | 484 expect(element.checked).toBe(true); |
| 641 | 485 |
| 642 scope.apply(() { | 486 scope.apply(() { |
| 643 scope.context['model'] = 0; | 487 scope.context['model'] = 0; |
| 644 }); | 488 }); |
| 645 expect(element.checked).toBe(false); | 489 expect(element.checked).toBe(false); |
| 646 | 490 |
| 647 element.checked = true; | 491 element.checked = true; |
| 648 _.triggerEvent(element, 'change'); | 492 _.triggerEvent(element, 'change'); |
| 649 expect(scope.context['model']).toBe(1); | 493 expect(scope.context['model']).toBe(1); |
| 650 | 494 |
| 651 element.checked = false; | 495 element.checked = false; |
| 652 _.triggerEvent(element, 'change'); | 496 _.triggerEvent(element, 'change'); |
| 653 expect(scope.context['model']).toBe(0); | 497 expect(scope.context['model']).toBe(0); |
| 654 }); | 498 })); |
| 655 | 499 |
| 656 it('should allow non boolean values like null, 0, 1', (Scope scope) { | 500 |
| 501 it('should allow non boolean values like null, 0, 1', inject((Scope scope)
{ |
| 657 var element = _.compile('<input type="checkbox" ng-model="model">'); | 502 var element = _.compile('<input type="checkbox" ng-model="model">'); |
| 658 | 503 |
| 659 scope.apply(() { | 504 scope.apply(() { |
| 660 scope.context['model'] = 0; | 505 scope.context['model'] = 0; |
| 661 }); | 506 }); |
| 662 expect(element.checked).toBe(false); | 507 expect(element.checked).toBe(false); |
| 663 | 508 |
| 664 scope.apply(() { | 509 scope.apply(() { |
| 665 scope.context['model'] = 1; | 510 scope.context['model'] = 1; |
| 666 }); | 511 }); |
| 667 expect(element.checked).toBe(true); | 512 expect(element.checked).toBe(true); |
| 668 | 513 |
| 669 scope.apply(() { | 514 scope.apply(() { |
| 670 scope.context['model'] = null; | 515 scope.context['model'] = null; |
| 671 }); | 516 }); |
| 672 expect(element.checked).toBe(false); | 517 expect(element.checked).toBe(false); |
| 673 }); | 518 })); |
| 674 | 519 |
| 675 it('should update model from the input value', (Scope scope) { | 520 |
| 521 it('should update model from the input value', inject((Scope scope) { |
| 676 var element = _.compile('<input type="checkbox" ng-model="model">'); | 522 var element = _.compile('<input type="checkbox" ng-model="model">'); |
| 677 | 523 |
| 678 element.checked = true; | 524 element.checked = true; |
| 679 _.triggerEvent(element, 'change'); | 525 _.triggerEvent(element, 'change'); |
| 680 expect(scope.context['model']).toBe(true); | 526 expect(scope.context['model']).toBe(true); |
| 681 | 527 |
| 682 element.checked = false; | 528 element.checked = false; |
| 683 _.triggerEvent(element, 'change'); | 529 _.triggerEvent(element, 'change'); |
| 684 expect(scope.context['model']).toBe(false); | 530 expect(scope.context['model']).toBe(false); |
| 685 }); | 531 })); |
| 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 }); | |
| 719 }); | 532 }); |
| 720 | 533 |
| 721 describe('textarea', () { | 534 describe('textarea', () { |
| 722 it('should update textarea value from model', () { | 535 it('should update textarea value from model', inject(() { |
| 723 _.compile('<textarea ng-model="model">'); | 536 _.compile('<textarea ng-model="model">'); |
| 724 _.rootScope.apply(); | 537 _.rootScope.apply(); |
| 725 | 538 |
| 726 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | 539 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
| 727 | 540 |
| 728 _.rootScope.apply('model = "misko"'); | 541 _.rootScope.apply('model = "misko"'); |
| 729 expect((_.rootElement as dom.TextAreaElement).value).toEqual('misko'); | 542 expect((_.rootElement as dom.TextAreaElement).value).toEqual('misko'); |
| 730 }); | 543 })); |
| 731 | 544 |
| 732 it('should render null as the empty string', () { | 545 it('should render null as the empty string', inject(() { |
| 733 _.compile('<textarea ng-model="model">'); | 546 _.compile('<textarea ng-model="model">'); |
| 734 _.rootScope.apply(); | 547 _.rootScope.apply(); |
| 735 | 548 |
| 736 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | 549 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
| 737 | 550 |
| 738 _.rootScope.apply('model = null'); | 551 _.rootScope.apply('model = null'); |
| 739 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); | 552 expect((_.rootElement as dom.TextAreaElement).value).toEqual(''); |
| 740 }); | 553 })); |
| 741 | 554 |
| 742 it('should update model from the input value', () { | 555 it('should update model from the input value', inject(() { |
| 743 _.compile('<textarea ng-model="model" probe="p">'); | 556 _.compile('<textarea ng-model="model" probe="p">'); |
| 744 Probe probe = _.rootScope.context['p']; | 557 Probe probe = _.rootScope.context['p']; |
| 745 var ngModel = probe.directive(NgModel); | 558 var ngModel = probe.directive(NgModel); |
| 746 TextAreaElement element = probe.element; | 559 TextAreaElement element = probe.element; |
| 747 | 560 |
| 748 element.value = 'abc'; | 561 element.value = 'abc'; |
| 749 _.triggerEvent(element, 'change'); | 562 _.triggerEvent(element, 'change'); |
| 750 expect(_.rootScope.context['model']).toEqual('abc'); | 563 expect(_.rootScope.context['model']).toEqual('abc'); |
| 751 | 564 |
| 752 element.value = 'def'; | 565 element.value = 'def'; |
| 753 var textarea = probe.directive(InputTextLike); | 566 var textarea = probe.directive(InputTextLikeDirective); |
| 754 textarea.processValue(); | 567 textarea.processValue(); |
| 755 expect(_.rootScope.context['model']).toEqual('def'); | 568 expect(_.rootScope.context['model']).toEqual('def'); |
| 756 | 569 |
| 757 }); | 570 })); |
| 758 | 571 |
| 759 // NOTE(deboer): This test passes on Dartium, but fails in the content_she
ll. | 572 // NOTE(deboer): This test passes on Dartium, but fails in the content_she
ll. |
| 760 // The Dart team is looking into this bug. | 573 // The Dart team is looking into this bug. |
| 761 xit('should write to input only if value is different', | 574 xit('should write to input only if value is different', inject((Injector i
, AstParser parser) { |
| 762 (Injector i, Animate animate) { | |
| 763 | |
| 764 var scope = _.rootScope; | 575 var scope = _.rootScope; |
| 765 var element = new dom.TextAreaElement(); | 576 var element = new dom.TextAreaElement(); |
| 766 var ngElement = new NgElement(element, scope, animate); | |
| 767 | |
| 768 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); | 577 NodeAttrs nodeAttrs = new NodeAttrs(new DivElement()); |
| 769 nodeAttrs['ng-model'] = 'model'; | 578 nodeAttrs['ng-model'] = 'model'; |
| 770 var model = new NgModel(scope, ngElement, i.createChild([new Module()]), | 579 var model = new NgModel(scope, element, i.createChild([new Module()]), n
ew NgNullForm(), parser, nodeAttrs); |
| 771 nodeAttrs, new Animate()); | |
| 772 dom.querySelector('body').append(element); | 580 dom.querySelector('body').append(element); |
| 773 var input = new InputTextLike(element, model, scope); | 581 var input = new InputTextLikeDirective(element, model, scope); |
| 774 | 582 |
| 775 element | 583 element |
| 776 ..value = 'abc' | 584 ..value = 'abc' |
| 777 ..selectionStart = 1 | 585 ..selectionStart = 1 |
| 778 ..selectionEnd = 2; | 586 ..selectionEnd = 2; |
| 779 | 587 |
| 780 model.render('abc'); | 588 model.render('abc'); |
| 781 | 589 |
| 782 expect(element.value).toEqual('abc'); | 590 expect(element.value).toEqual('abc'); |
| 783 expect(element.selectionStart).toEqual(1); | 591 expect(element.selectionStart).toEqual(1); |
| 784 expect(element.selectionEnd).toEqual(2); | 592 expect(element.selectionEnd).toEqual(2); |
| 785 | 593 |
| 786 model.render('xyz'); | 594 model.render('xyz'); |
| 787 | 595 |
| 788 // Setting the value on a textarea doesn't update the selection the way
it | 596 // Setting the value on a textarea doesn't update the selection the way
it |
| 789 // does on input elements. This stays unchanged. | 597 // does on input elements. This stays unchanged. |
| 790 expect(element.value).toEqual('xyz'); | 598 expect(element.value).toEqual('xyz'); |
| 791 expect(element.selectionStart).toEqual(0); | 599 expect(element.selectionStart).toEqual(0); |
| 792 expect(element.selectionEnd).toEqual(0); | 600 expect(element.selectionEnd).toEqual(0); |
| 793 }); | 601 })); |
| 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 }); | |
| 810 }); | 602 }); |
| 811 | 603 |
| 812 describe('type="radio"', () { | 604 describe('type="radio"', () { |
| 813 it('should update input value from model', () { | 605 it('should update input value from model', inject(() { |
| 814 _.compile('<input type="radio" name="color" value="red" ng-model="color"
probe="r">' + | 606 _.compile('<input type="radio" name="color" value="red" ng-model="color"
probe="r">' + |
| 815 '<input type="radio" name="color" value="green" ng-model="colo
r" probe="g">' + | 607 '<input type="radio" name="color" value="green" ng-model="colo
r" probe="g">' + |
| 816 '<input type="radio" name="color" value="blue" ng-model="color
" probe="b">'); | 608 '<input type="radio" name="color" value="blue" ng-model="color
" probe="b">'); |
| 817 _.rootScope.apply(); | 609 _.rootScope.apply(); |
| 818 | 610 |
| 819 RadioButtonInputElement redBtn = _.rootScope.context['r'].element; | 611 RadioButtonInputElement redBtn = _.rootScope.context['r'].element; |
| 820 RadioButtonInputElement greenBtn = _.rootScope.context['g'].element; | 612 RadioButtonInputElement greenBtn = _.rootScope.context['g'].element; |
| 821 RadioButtonInputElement blueBtn = _.rootScope.context['b'].element; | 613 RadioButtonInputElement blueBtn = _.rootScope.context['b'].element; |
| 822 | 614 |
| 823 expect(redBtn.checked).toBe(false); | 615 expect(redBtn.checked).toBe(false); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 844 expect(_.rootScope.context['color']).toEqual('red'); | 636 expect(_.rootScope.context['color']).toEqual('red'); |
| 845 expect(redBtn.checked).toBe(true); | 637 expect(redBtn.checked).toBe(true); |
| 846 expect(greenBtn.checked).toBe(false); | 638 expect(greenBtn.checked).toBe(false); |
| 847 expect(blueBtn.checked).toBe(false); | 639 expect(blueBtn.checked).toBe(false); |
| 848 | 640 |
| 849 _.triggerEvent(greenBtn, 'click'); | 641 _.triggerEvent(greenBtn, 'click'); |
| 850 expect(_.rootScope.context['color']).toEqual('green'); | 642 expect(_.rootScope.context['color']).toEqual('green'); |
| 851 expect(redBtn.checked).toBe(false); | 643 expect(redBtn.checked).toBe(false); |
| 852 expect(greenBtn.checked).toBe(true); | 644 expect(greenBtn.checked).toBe(true); |
| 853 expect(blueBtn.checked).toBe(false); | 645 expect(blueBtn.checked).toBe(false); |
| 854 }); | 646 })); |
| 855 | 647 |
| 856 it('should support ng-value', () { | 648 it('should support ng-value', () { |
| 857 _.compile('<input type="radio" name="color" ng-value="red" ng-model="col
or" probe="r">' + | 649 _.compile('<input type="radio" name="color" ng-value="red" ng-model="col
or" probe="r">' + |
| 858 '<input type="radio" name="color" ng-value="green" ng-model="c
olor" probe="g">' + | 650 '<input type="radio" name="color" ng-value="green" ng-model="c
olor" probe="g">' + |
| 859 '<input type="radio" name="color" ng-value="blue" ng-model="co
lor" probe="b">'); | 651 '<input type="radio" name="color" ng-value="blue" ng-model="co
lor" probe="b">'); |
| 860 | 652 |
| 861 var red = {'name': 'RED'}; | 653 var red = {'name': 'RED'}; |
| 862 var green = {'name': 'GREEN'}; | 654 var green = {'name': 'GREEN'}; |
| 863 var blue = {'name': 'BLUE'}; | 655 var blue = {'name': 'BLUE'}; |
| 864 _.rootScope.context | 656 _.rootScope.context |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 900 expect(greenBtn.checked).toBe(false); | 692 expect(greenBtn.checked).toBe(false); |
| 901 expect(blueBtn.checked).toBe(false); | 693 expect(blueBtn.checked).toBe(false); |
| 902 | 694 |
| 903 _.triggerEvent(greenBtn, 'click'); | 695 _.triggerEvent(greenBtn, 'click'); |
| 904 expect(_.rootScope.context['color']).toEqual(green); | 696 expect(_.rootScope.context['color']).toEqual(green); |
| 905 expect(redBtn.checked).toBe(false); | 697 expect(redBtn.checked).toBe(false); |
| 906 expect(greenBtn.checked).toBe(true); | 698 expect(greenBtn.checked).toBe(true); |
| 907 expect(blueBtn.checked).toBe(false); | 699 expect(blueBtn.checked).toBe(false); |
| 908 }); | 700 }); |
| 909 | 701 |
| 910 it('should render as dirty when checked', (Scope scope) { | 702 it('should render as dirty when checked', inject((Scope scope) { |
| 911 var element = _.compile( | 703 var element = _.compile( |
| 912 '<div>' + | 704 '<div>' + |
| 913 ' <input type="radio" id="on" ng-model="my_model" probe="i" value="on
" />' + | 705 ' <input type="radio" id="on" ng-model="my_model" probe="i" value="on
" />' + |
| 914 ' <input type="radio" id="off" ng-model="my_model" probe="j" value="o
ff" />' + | 706 ' <input type="radio" id="off" ng-model="my_model" probe="j" value="o
ff" />' + |
| 915 '</div>' | 707 '</div>' |
| 916 ); | 708 ); |
| 917 Probe probe = _.rootScope.context['i']; | 709 Probe probe = _.rootScope.context['i']; |
| 918 | 710 |
| 919 var model = probe.directive(NgModel); | 711 var model = probe.directive(NgModel); |
| 920 | 712 |
| 921 var input1 = element.querySelector("#on"); | 713 var input1 = element.querySelector("#on"); |
| 922 var input2 = element.querySelector("#off"); | 714 var input2 = element.querySelector("#off"); |
| 923 | 715 |
| 924 scope.apply(); | |
| 925 | |
| 926 expect(model.pristine).toEqual(true); | 716 expect(model.pristine).toEqual(true); |
| 927 expect(model.dirty).toEqual(false); | 717 expect(model.dirty).toEqual(false); |
| 928 | 718 |
| 929 expect(input1.classes.contains("ng-dirty")).toBe(false); | 719 expect(input1.classes.contains("ng-dirty")).toBe(false); |
| 930 expect(input2.classes.contains("ng-dirty")).toBe(false); | 720 expect(input2.classes.contains("ng-dirty")).toBe(false); |
| 931 expect(input1.classes.contains("ng-pristine")).toBe(true); | 721 expect(input1.classes.contains("ng-pristine")).toBe(true); |
| 932 expect(input1.classes.contains("ng-pristine")).toBe(true); | 722 expect(input1.classes.contains("ng-pristine")).toBe(true); |
| 933 | 723 |
| 934 input1.checked = true; | 724 input1.checked = true; |
| 935 _.triggerEvent(input1, 'click'); | 725 _.triggerEvent(input1, 'click'); |
| 936 scope.apply(); | |
| 937 | 726 |
| 938 expect(model.pristine).toEqual(false); | 727 expect(model.pristine).toEqual(false); |
| 939 expect(model.dirty).toEqual(true); | 728 expect(model.dirty).toEqual(true); |
| 940 | 729 |
| 941 input1.checked = false; | 730 input1.checked = false; |
| 942 input2.checked = true; | 731 input2.checked = true; |
| 943 _.triggerEvent(input2, 'click'); | 732 _.triggerEvent(input2, 'click'); |
| 944 scope.apply(); | |
| 945 | 733 |
| 946 expect(input1.classes.contains("ng-dirty")).toBe(true); | 734 expect(input1.classes.contains("ng-dirty")).toBe(true); |
| 947 expect(input2.classes.contains("ng-dirty")).toBe(true); | 735 expect(input2.classes.contains("ng-dirty")).toBe(true); |
| 948 expect(input1.classes.contains("ng-pristine")).toBe(false); | 736 expect(input1.classes.contains("ng-pristine")).toBe(false); |
| 949 expect(input1.classes.contains("ng-pristine")).toBe(false); | 737 expect(input1.classes.contains("ng-pristine")).toBe(false); |
| 950 }); | 738 })); |
| 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 }); | |
| 979 }); | 739 }); |
| 980 | 740 |
| 981 describe('type="search"', () { | 741 describe('type="search"', () { |
| 982 it('should update input value from model', () { | 742 it('should update input value from model', inject(() { |
| 983 _.compile('<input type="search" ng-model="model">'); | 743 _.compile('<input type="search" ng-model="model">'); |
| 984 _.rootScope.apply(); | 744 _.rootScope.apply(); |
| 985 | 745 |
| 986 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 746 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 987 | 747 |
| 988 _.rootScope.apply('model = "matias"'); | 748 _.rootScope.apply('model = "matias"'); |
| 989 expect((_.rootElement as dom.InputElement).value).toEqual('matias'); | 749 expect((_.rootElement as dom.InputElement).value).toEqual('matias'); |
| 990 }); | 750 })); |
| 991 | 751 |
| 992 it('should render null as the empty string', () { | 752 it('should render null as the empty string', inject(() { |
| 993 _.compile('<input type="search" ng-model="model">'); | 753 _.compile('<input type="search" ng-model="model">'); |
| 994 _.rootScope.apply(); | 754 _.rootScope.apply(); |
| 995 | 755 |
| 996 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 756 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 997 | 757 |
| 998 _.rootScope.apply('model = null'); | 758 _.rootScope.apply('model = null'); |
| 999 expect((_.rootElement as dom.InputElement).value).toEqual(''); | 759 expect((_.rootElement as dom.InputElement).value).toEqual(''); |
| 1000 }); | 760 })); |
| 1001 | 761 |
| 1002 it('should update model from the input value', () { | 762 it('should update model from the input value', inject(() { |
| 1003 _.compile('<input type="search" ng-model="model" probe="p">'); | 763 _.compile('<input type="search" ng-model="model" probe="p">'); |
| 1004 Probe probe = _.rootScope.context['p']; | 764 Probe probe = _.rootScope.context['p']; |
| 1005 var ngModel = probe.directive(NgModel); | 765 var ngModel = probe.directive(NgModel); |
| 1006 InputElement inputElement = probe.element; | 766 InputElement inputElement = probe.element; |
| 1007 | 767 |
| 1008 inputElement.value = 'xzy'; | 768 inputElement.value = 'xzy'; |
| 1009 _.triggerEvent(inputElement, 'change'); | 769 _.triggerEvent(inputElement, 'change'); |
| 1010 expect(_.rootScope.context['model']).toEqual('xzy'); | 770 expect(_.rootScope.context['model']).toEqual('xzy'); |
| 1011 | 771 |
| 1012 inputElement.value = '123'; | 772 inputElement.value = '123'; |
| 1013 var input = probe.directive(InputTextLike); | 773 var input = probe.directive(InputTextLikeDirective); |
| 1014 input.processValue(); | 774 input.processValue(); |
| 1015 expect(_.rootScope.context['model']).toEqual('123'); | 775 expect(_.rootScope.context['model']).toEqual('123'); |
| 1016 }); | 776 })); |
| 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 }); | |
| 1033 }); | 777 }); |
| 1034 | 778 |
| 1035 describe('contenteditable', () { | 779 describe('contenteditable', () { |
| 1036 it('should update content from model', () { | 780 it('should update content from model', inject(() { |
| 1037 _.compile('<p contenteditable ng-model="model">'); | 781 _.compile('<p contenteditable ng-model="model">'); |
| 1038 _.rootScope.apply(); | 782 _.rootScope.apply(); |
| 1039 | 783 |
| 1040 expect(_.rootElement.text).toEqual(''); | 784 expect(_.rootElement.text).toEqual(''); |
| 1041 | 785 |
| 1042 _.rootScope.apply('model = "misko"'); | 786 _.rootScope.apply('model = "misko"'); |
| 1043 expect(_.rootElement.text).toEqual('misko'); | 787 expect(_.rootElement.text).toEqual('misko'); |
| 1044 }); | 788 })); |
| 1045 | 789 |
| 1046 it('should update model from the input value', () { | 790 it('should update model from the input value', inject(() { |
| 1047 _.compile('<p contenteditable ng-model="model">'); | 791 _.compile('<p contenteditable ng-model="model">'); |
| 1048 Element element = _.rootElement; | 792 Element element = _.rootElement; |
| 1049 | 793 |
| 1050 element.innerHtml = 'abc'; | 794 element.innerHtml = 'abc'; |
| 1051 _.triggerEvent(element, 'change'); | 795 _.triggerEvent(element, 'change'); |
| 1052 expect(_.rootScope.context['model']).toEqual('abc'); | 796 expect(_.rootScope.context['model']).toEqual('abc'); |
| 1053 | 797 |
| 1054 element.innerHtml = 'def'; | 798 element.innerHtml = 'def'; |
| 1055 var input = ngInjector(element).get(ContentEditable); | 799 var input = ngInjector(element).get(ContentEditableDirective); |
| 1056 input.processValue(); | 800 input.processValue(); |
| 1057 expect(_.rootScope.context['model']).toEqual('def'); | 801 expect(_.rootScope.context['model']).toEqual('def'); |
| 1058 }); | 802 })); |
| 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 }); | |
| 1075 }); | 803 }); |
| 1076 | 804 |
| 1077 describe('pristine / dirty', () { | 805 describe('pristine / dirty', () { |
| 1078 it('should be set to pristine by default', (Scope scope) { | 806 it('should be set to pristine by default', inject((Scope scope) { |
| 1079 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 807 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 1080 Probe probe = _.rootScope.context['i']; | 808 Probe probe = _.rootScope.context['i']; |
| 1081 var model = probe.directive(NgModel); | 809 var model = probe.directive(NgModel); |
| 1082 | 810 |
| 1083 expect(model.pristine).toEqual(true); | 811 expect(model.pristine).toEqual(true); |
| 1084 expect(model.dirty).toEqual(false); | 812 expect(model.dirty).toEqual(false); |
| 1085 }); | 813 })); |
| 1086 | 814 |
| 1087 it('should add and remove the correct CSS classes when set to dirty and to
pristine', (Scope scope) { | 815 it('should add and remove the correct CSS classes when set to dirty and to
pristine', inject((Scope scope) { |
| 1088 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 816 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 1089 Probe probe = _.rootScope.context['i']; | 817 Probe probe = _.rootScope.context['i']; |
| 1090 NgModel model = probe.directive(NgModel); | 818 NgModel model = probe.directive(NgModel); |
| 1091 InputElement element = probe.element; | 819 InputElement element = probe.element; |
| 1092 | 820 |
| 1093 model.addInfo('ng-dirty'); | 821 model.dirty = true; |
| 1094 scope.apply(); | |
| 1095 | |
| 1096 expect(model.pristine).toEqual(false); | 822 expect(model.pristine).toEqual(false); |
| 1097 expect(model.dirty).toEqual(true); | 823 expect(model.dirty).toEqual(true); |
| 1098 expect(element).not.toHaveClass('ng-pristine'); | 824 expect(element.classes.contains('ng-pristine')).toBe(false); |
| 1099 expect(element).toHaveClass('ng-dirty'); | 825 expect(element.classes.contains('ng-dirty')).toBe(true); |
| 1100 | 826 |
| 1101 model.removeInfo('ng-dirty'); | 827 model.pristine = true; |
| 1102 scope.apply(); | |
| 1103 | |
| 1104 expect(model.pristine).toEqual(true); | 828 expect(model.pristine).toEqual(true); |
| 1105 expect(model.dirty).toEqual(false); | 829 expect(model.dirty).toEqual(false); |
| 1106 expect(element).toHaveClass('ng-pristine'); | 830 expect(element.classes.contains('ng-pristine')).toBe(true); |
| 1107 expect(element).not.toHaveClass('ng-dirty'); | 831 expect(element.classes.contains('ng-dirty')).toBe(false); |
| 1108 }); | 832 })); |
| 1109 | 833 |
| 1110 // TODO(matias): figure out why the 2nd apply is optional | 834 it('should render the parent form/fieldset as dirty but not the other mode
ls', inject((Scope scope) { |
| 1111 it('should render the parent form/fieldset as dirty but not the other mode
ls', | |
| 1112 (Scope scope) { | |
| 1113 | |
| 1114 _.compile('<form name="myForm">' + | 835 _.compile('<form name="myForm">' + |
| 1115 ' <fieldset name="myFieldset">' + | 836 ' <fieldset name="myFieldset">' + |
| 1116 ' <input type="text" ng-model="my_model1" probe="myModel1"
/>' + | 837 ' <input type="text" ng-model="my_model1" probe="myModel1"
/>' + |
| 1117 ' <input type="text" ng-model="my_model2" probe="myModel2"
/>' + | 838 ' <input type="text" ng-model="my_model2" probe="myModel2"
/>' + |
| 1118 ' </fieldset>' + | 839 ' </fieldset>' + |
| 1119 '</form>'); | 840 '</form>'); |
| 1120 | 841 |
| 1121 var formElement = _.rootScope.context['myForm'].element.node; | |
| 1122 var fieldsetElement = _.rootScope.context['myFieldset'].element.node; | |
| 1123 var inputElement1 = _.rootScope.context['myModel1'].element; | 842 var inputElement1 = _.rootScope.context['myModel1'].element; |
| 1124 var inputElement2 = _.rootScope.context['myModel2'].element; | 843 var inputElement2 = _.rootScope.context['myModel2'].element; |
| 844 var formElement = _.rootScope.context['myForm'].element; |
| 845 var fieldsetElement = _.rootScope.context['myFieldset'].element; |
| 1125 | 846 |
| 1126 scope.apply(); | 847 expect(formElement.classes.contains('ng-pristine')).toBe(true); |
| 848 expect(formElement.classes.contains('ng-dirty')).toBe(false); |
| 1127 | 849 |
| 1128 expect(formElement).toHaveClass('ng-pristine'); | 850 expect(fieldsetElement.classes.contains('ng-pristine')).toBe(true); |
| 1129 expect(formElement).not.toHaveClass('ng-dirty'); | 851 expect(fieldsetElement.classes.contains('ng-dirty')).toBe(false); |
| 1130 | 852 |
| 1131 expect(fieldsetElement).toHaveClass('ng-pristine'); | 853 expect(inputElement1.classes.contains('ng-pristine')).toBe(true); |
| 1132 expect(fieldsetElement).not.toHaveClass('ng-dirty'); | 854 expect(inputElement1.classes.contains('ng-dirty')).toBe(false); |
| 1133 | 855 |
| 1134 expect(inputElement1).toHaveClass('ng-pristine'); | 856 expect(inputElement2.classes.contains('ng-pristine')).toBe(true); |
| 1135 expect(inputElement1).not.toHaveClass('ng-dirty'); | 857 expect(inputElement2.classes.contains('ng-dirty')).toBe(false); |
| 1136 | |
| 1137 expect(inputElement2).toHaveClass('ng-pristine'); | |
| 1138 expect(inputElement2).not.toHaveClass('ng-dirty'); | |
| 1139 | 858 |
| 1140 inputElement1.value = '...hi...'; | 859 inputElement1.value = '...hi...'; |
| 1141 _.triggerEvent(inputElement1, 'change'); | 860 _.triggerEvent(inputElement1, 'change'); |
| 1142 scope.apply(); | |
| 1143 | 861 |
| 1144 expect(formElement).not.toHaveClass('ng-pristine'); | 862 expect(formElement.classes.contains('ng-pristine')).toBe(false); |
| 1145 expect(formElement).toHaveClass('ng-dirty'); | 863 expect(formElement.classes.contains('ng-dirty')).toBe(true); |
| 1146 | 864 |
| 1147 expect(fieldsetElement).not.toHaveClass('ng-pristine'); | 865 expect(fieldsetElement.classes.contains('ng-pristine')).toBe(false); |
| 1148 expect(fieldsetElement).toHaveClass('ng-dirty'); | 866 expect(fieldsetElement.classes.contains('ng-dirty')).toBe(true); |
| 1149 | 867 |
| 1150 expect(inputElement1).not.toHaveClass('ng-pristine'); | 868 expect(inputElement1.classes.contains('ng-pristine')).toBe(false); |
| 1151 expect(inputElement1).toHaveClass('ng-dirty'); | 869 expect(inputElement1.classes.contains('ng-dirty')).toBe(true); |
| 1152 | 870 |
| 1153 expect(inputElement2).toHaveClass('ng-pristine'); | 871 expect(inputElement2.classes.contains('ng-pristine')).toBe(true); |
| 1154 expect(inputElement2).not.toHaveClass('ng-dirty'); | 872 expect(inputElement2.classes.contains('ng-dirty')).toBe(false); |
| 1155 }); | 873 })); |
| 1156 }); | 874 }); |
| 1157 | 875 |
| 1158 describe('validation', () { | 876 describe('validation', () { |
| 1159 it('should happen automatically when the scope changes', (Scope scope) { | 877 it('should happen automatically when the scope changes', inject((Scope sco
pe) { |
| 1160 _.compile('<input type="text" ng-model="model" probe="i" required>'); | 878 _.compile('<input type="text" ng-model="model" probe="i" required>'); |
| 1161 _.rootScope.apply(); | 879 _.rootScope.apply(); |
| 1162 | 880 |
| 1163 Probe probe = _.rootScope.context['i']; | 881 Probe probe = _.rootScope.context['i']; |
| 1164 var model = probe.directive(NgModel); | 882 var model = probe.directive(NgModel); |
| 1165 | 883 |
| 1166 expect(model.invalid).toBe(true); | 884 expect(model.invalid).toBe(true); |
| 1167 expect(model.valid).toBe(false); | 885 expect(model.valid).toBe(false); |
| 1168 | 886 |
| 1169 _.rootScope.apply('model = "viljami"'); | 887 _.rootScope.apply('model = "viljami"'); |
| 1170 | 888 |
| 1171 expect(model.invalid).toBe(false); | 889 expect(model.invalid).toBe(false); |
| 1172 expect(model.valid).toBe(true); | 890 expect(model.valid).toBe(true); |
| 1173 }); | 891 })); |
| 1174 | 892 |
| 1175 it('should happen automatically upon user input via the onInput event', ()
{ | 893 it('should happen automatically upon user input via the onInput event', in
ject(() { |
| 1176 _.compile('<input type="text" ng-model="model" probe="i" required>'); | 894 _.compile('<input type="text" ng-model="model" probe="i" required>'); |
| 1177 _.rootScope.apply(); | |
| 1178 | 895 |
| 1179 Probe probe = _.rootScope.context['i']; | 896 Probe probe = _.rootScope.context['i']; |
| 1180 var model = probe.directive(NgModel); | 897 var model = probe.directive(NgModel); |
| 1181 InputElement inputElement = model.element.node; | 898 InputElement inputElement = model.element; |
| 1182 | 899 |
| 1183 expect(model.invalid).toBe(true); | 900 expect(model.invalid).toBe(true); |
| 1184 expect(model.valid).toBe(false); | 901 expect(model.valid).toBe(false); |
| 1185 | 902 |
| 1186 inputElement.value = 'some value'; | 903 inputElement.value = 'some value'; |
| 1187 _.triggerEvent(inputElement, 'input'); | 904 _.triggerEvent(inputElement, 'input'); |
| 1188 | 905 |
| 1189 expect(model.invalid).toBe(false); | 906 expect(model.invalid).toBe(false); |
| 1190 expect(model.valid).toBe(true); | 907 expect(model.valid).toBe(true); |
| 1191 }); | 908 })); |
| 1192 }); | 909 }); |
| 1193 | 910 |
| 1194 describe('valid / invalid', () { | 911 describe('valid / invalid', () { |
| 1195 it('should add and remove the correct flags when set to valid and to inval
id', (Scope scope) { | 912 it('should add and remove the correct flags when set to valid and to inval
id', inject((Scope scope) { |
| 1196 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 913 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 1197 Probe probe = _.rootScope.context['i']; | 914 Probe probe = _.rootScope.context['i']; |
| 1198 var model = probe.directive(NgModel); | 915 var model = probe.directive(NgModel); |
| 1199 InputElement element = probe.element; | 916 InputElement element = probe.element; |
| 1200 | 917 |
| 1201 model.addError('ng-required'); | 918 model.invalid = true; |
| 1202 model.validate(); | |
| 1203 scope.apply(); | |
| 1204 | |
| 1205 expect(model.valid).toEqual(false); | 919 expect(model.valid).toEqual(false); |
| 1206 expect(model.invalid).toEqual(true); | 920 expect(model.invalid).toEqual(true); |
| 1207 //expect(element).not.toHaveClass('ng-valid'); | 921 expect(element.classes.contains('ng-valid')).toBe(false); |
| 1208 expect(element).toHaveClass('ng-invalid'); | 922 expect(element.classes.contains('ng-invalid')).toBe(true); |
| 1209 | 923 |
| 1210 model.removeError('ng-required'); | 924 model.valid = true; |
| 1211 model.validate(); | |
| 1212 scope.apply(); | |
| 1213 | |
| 1214 expect(model.valid).toEqual(true); | 925 expect(model.valid).toEqual(true); |
| 1215 expect(model.invalid).toEqual(false); | 926 expect(model.invalid).toEqual(false); |
| 1216 expect(element).not.toHaveClass('ng-invalid'); | 927 expect(element.classes.contains('ng-invalid')).toBe(false); |
| 1217 // expect(element).toHaveClass('ng-valid'); | 928 expect(element.classes.contains('ng-valid')).toBe(true); |
| 1218 }); | 929 })); |
| 1219 | 930 |
| 1220 it('should set the validity with respect to all existing validations when
setValidity() is used', (Scope scope) { | 931 it('should set the validity with respect to all existing validations when
setValidity() is used', inject((Scope scope) { |
| 1221 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 932 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 1222 Probe probe = _.rootScope.context['i']; | 933 Probe probe = _.rootScope.context['i']; |
| 1223 var model = probe.directive(NgModel); | 934 var model = probe.directive(NgModel); |
| 1224 | 935 |
| 1225 model.addError("required"); | 936 model.setValidity("required", false); |
| 1226 expect(model.valid).toEqual(false); | 937 expect(model.valid).toEqual(false); |
| 1227 expect(model.invalid).toEqual(true); | 938 expect(model.invalid).toEqual(true); |
| 1228 | 939 |
| 1229 model.addError("format"); | 940 model.setValidity("format", false); |
| 1230 expect(model.valid).toEqual(false); | 941 expect(model.valid).toEqual(false); |
| 1231 expect(model.invalid).toEqual(true); | 942 expect(model.invalid).toEqual(true); |
| 1232 | 943 |
| 1233 model.removeError("format"); | 944 model.setValidity("format", true); |
| 1234 expect(model.valid).toEqual(false); | 945 expect(model.valid).toEqual(false); |
| 1235 expect(model.invalid).toEqual(true); | 946 expect(model.invalid).toEqual(true); |
| 1236 | 947 |
| 1237 model.removeError("required"); | 948 model.setValidity("required", true); |
| 1238 expect(model.valid).toEqual(true); | 949 expect(model.valid).toEqual(true); |
| 1239 expect(model.invalid).toEqual(false); | 950 expect(model.invalid).toEqual(false); |
| 1240 }); | 951 })); |
| 1241 | 952 |
| 1242 it('should register each error only once when invalid', (Scope scope) { | 953 it('should register each error only once when invalid', inject((Scope scop
e) { |
| 1243 _.compile('<input type="text" ng-model="my_model" probe="i" />'); | 954 _.compile('<input type="text" ng-model="my_model" probe="i" />'); |
| 1244 Probe probe = _.rootScope.context['i']; | 955 Probe probe = _.rootScope.context['i']; |
| 1245 var model = probe.directive(NgModel); | 956 var model = probe.directive(NgModel); |
| 1246 | 957 |
| 1247 model.addError("distinct-error"); | 958 model.setValidity("distinct-error", false); |
| 1248 expect(model.valid).toEqual(false); | 959 expect(model.valid).toEqual(false); |
| 1249 expect(model.invalid).toEqual(true); | 960 expect(model.invalid).toEqual(true); |
| 1250 | 961 |
| 1251 model.addError("distinct-error"); | 962 model.setValidity("distinct-error", false); |
| 1252 expect(model.valid).toEqual(false); | 963 expect(model.valid).toEqual(false); |
| 1253 expect(model.invalid).toEqual(true); | 964 expect(model.invalid).toEqual(true); |
| 1254 | 965 |
| 1255 model.removeError("distinct-error"); | 966 model.setValidity("distinct-error", true); |
| 1256 expect(model.valid).toEqual(true); | 967 expect(model.valid).toEqual(true); |
| 1257 expect(model.invalid).toEqual(false); | 968 expect(model.invalid).toEqual(false); |
| 1258 }); | 969 })); |
| 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 }); | |
| 1281 }); | 970 }); |
| 1282 | 971 |
| 1283 describe('text-like events', () { | 972 describe('text-like events', () { |
| 1284 it('should update the binding on the "input" event', () { | 973 it('should update the binding on the "input" event', inject(() { |
| 1285 _.compile('<input type="text" ng-model="model" probe="p">'); | 974 _.compile('<input type="text" ng-model="model" probe="p">'); |
| 1286 Probe probe = _.rootScope.context['p']; | 975 Probe probe = _.rootScope.context['p']; |
| 1287 InputElement inputElement = probe.element; | 976 InputElement inputElement = probe.element; |
| 1288 | 977 |
| 1289 inputElement.value = 'waaaah'; | 978 inputElement.value = 'waaaah'; |
| 1290 | 979 |
| 1291 expect(_.rootScope.context['model']).not.toEqual('waaaah'); | 980 expect(_.rootScope.context['model']).not.toEqual('waaaah'); |
| 1292 | 981 |
| 1293 _.triggerEvent(inputElement, 'input'); | 982 _.triggerEvent(inputElement, 'input'); |
| 1294 | 983 |
| 1295 expect(_.rootScope.context['model']).toEqual('waaaah'); | 984 expect(_.rootScope.context['model']).toEqual('waaaah'); |
| 1296 }); | 985 })); |
| 1297 }); | 986 }); |
| 1298 | 987 |
| 1299 describe('error messages', () { | 988 describe('error messages', () { |
| 1300 it('should produce a useful error for bad ng-model expressions', () { | 989 it('should produce a useful error for bad ng-model expressions', () { |
| 1301 expect(async(() { | 990 expect(async(() { |
| 1302 _.compile('<div no-love><textarea ng-model=ctrl.love probe="loveProbe"
></textarea></div'); | 991 _.compile('<div no-love><textarea ng-model=ctrl.love probe="loveProbe"
></textarea></div'); |
| 1303 Probe probe = _.rootScope.context['loveProbe']; | 992 Probe probe = _.rootScope.context['loveProbe']; |
| 1304 TextAreaElement inputElement = probe.element; | 993 TextAreaElement inputElement = probe.element; |
| 1305 | 994 |
| 1306 inputElement.value = 'xzy'; | 995 inputElement.value = 'xzy'; |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1347 _.triggerEvent(input, 'blur'); | 1036 _.triggerEvent(input, 'blur'); |
| 1348 | 1037 |
| 1349 expect(model.touched).toBe(true); | 1038 expect(model.touched).toBe(true); |
| 1350 expect(model.untouched).toBe(false); | 1039 expect(model.untouched).toBe(false); |
| 1351 | 1040 |
| 1352 model.reset(); | 1041 model.reset(); |
| 1353 | 1042 |
| 1354 expect(model.touched).toBe(false); | 1043 expect(model.touched).toBe(false); |
| 1355 expect(model.untouched).toBe(true); | 1044 expect(model.untouched).toBe(true); |
| 1356 }); | 1045 }); |
| 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 }); | |
| 1542 }); | 1046 }); |
| 1543 } | 1047 } |
| 1544 | 1048 |
| 1545 @Controller( | 1049 @NgController( |
| 1546 selector: '[no-love]', | 1050 selector: '[no-love]', |
| 1547 publishAs: 'ctrl') | 1051 publishAs: 'ctrl') |
| 1548 class ControllerWithNoLove { | 1052 class ControllerWithNoLove { |
| 1549 var apathy = null; | 1053 var apathy = null; |
| 1550 } | 1054 } |
| 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 |