From 058c8ee4017f45c46017c99d64fc192e6fab0137 Mon Sep 17 00:00:00 2001 From: Andrew Ryan Lazarus Date: Fri, 6 Dec 2013 13:54:32 -0800 Subject: [PATCH] feat(ng-model): implemented support for input[type=password] --- lib/directive/module.dart | 1 + lib/directive/ng_model.dart | 21 +++++++++++ test/directive/ng_model_spec.dart | 63 +++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/lib/directive/module.dart b/lib/directive/module.dart index 7cf33b1e0..eb85f15ec 100644 --- a/lib/directive/module.dart +++ b/lib/directive/module.dart @@ -49,6 +49,7 @@ class NgDirectiveModule extends Module { value(InputNumberDirective, null); value(InputRadioDirective, null); value(InputTextDirective, null); + value(InputPasswordDirective, null); value(InputUrlDirective, null); value(InputCheckboxDirective, null); value(TextAreaDirective, null); diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index 54185a142..14d5da574 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -144,6 +144,27 @@ class InputTextDirective extends _InputTextlikeDirective { } } +/** + * Usage: + * + * + * + * This creates a two way databinding between the expression specified in + * ng-model and the password input element in the DOM.  If the ng-model value is + * `null`, it is treated as equivalent to the empty string for rendering + * purposes. + */ +@NgDirective(selector: 'input[type=password][ng-model]') +class InputPasswordDirective extends _InputTextlikeDirective { + InputPasswordDirective(dom.Element inputElement, NgModel ngModel, Scope scope): + super(inputElement, ngModel, scope); + + String get typedValue => inputElement.value; + set typedValue(String value) { + inputElement.value = (value == null) ? '' : value; + } +} + /** * Usage: * diff --git a/test/directive/ng_model_spec.dart b/test/directive/ng_model_spec.dart index f37ec019f..29ce67611 100644 --- a/test/directive/ng_model_spec.dart +++ b/test/directive/ng_model_spec.dart @@ -72,6 +72,69 @@ describe('ng-model', () { })); }); + describe('type="password"', () { + it('should update input value from model', inject(() { + _.compile(''); + _.rootScope.$digest(); + + expect((_.rootElement as dom.InputElement).value).toEqual(''); + + _.rootScope.$apply('model = "misko"'); + expect((_.rootElement as dom.InputElement).value).toEqual('misko'); + })); + + it('should render null as the empty string', inject(() { + _.compile(''); + _.rootScope.$digest(); + + expect((_.rootElement as dom.InputElement).value).toEqual(''); + + _.rootScope.$apply('model = null'); + expect((_.rootElement as dom.InputElement).value).toEqual(''); + })); + + it('should update model from the input value', inject(() { + _.compile(''); + Probe probe = _.rootScope.p; + var ngModel = probe.directive(NgModel); + InputElement inputElement = probe.element; + + inputElement.value = 'abc'; + _.triggerEvent(inputElement, 'change'); + expect(_.rootScope.model).toEqual('abc'); + + inputElement.value = 'def'; + var input = probe.directive(InputPasswordDirective); + input.processValue(); + expect(_.rootScope.model).toEqual('def'); + + })); + + it('should write to input only if value is different', inject(() { + var scope = _.rootScope; + var model = new NgModel(scope, new NodeAttrs(new DivElement())); + var element = new dom.InputElement(); + dom.query('body').append(element); + var input = new InputPasswordDirective(element, model, scope); + + element.value = 'abc'; + element.selectionStart = 1; + element.selectionEnd = 2; + + model.render('abc'); + + expect(element.value).toEqual('abc'); + expect(element.selectionStart).toEqual(1); + expect(element.selectionEnd).toEqual(2); + + model.render('xyz'); + + expect(element.value).toEqual('xyz'); + expect(element.selectionStart).toEqual(1); + expect(element.selectionEnd).toEqual(2); + })); + }); + describe('type="checkbox"', () { it('should update input value from model', inject((Scope scope) { var element = _.compile('');