From afa97373409a8286a5d313b9a72d4dd13afb3dba Mon Sep 17 00:00:00 2001 From: Patrice Chalin Date: Wed, 2 Apr 2014 17:54:02 -0500 Subject: [PATCH] refactor(InputCheckboxDirective): fix API doc and refactor ng-true/false-value - Refactor `NgTrueValue` and `NgFalseValue` so that it smells good! - Refactor/clean-up InputCheckboxDirective. - Update `input[type=checkbox]` API doc to reflect AngularDart behavior. --- lib/directive/module.dart | 5 +- lib/directive/ng_model.dart | 85 ++++++++++++++++++------------- test/directive/ng_model_spec.dart | 20 ++++++-- 3 files changed, 69 insertions(+), 41 deletions(-) diff --git a/lib/directive/module.dart b/lib/directive/module.dart index 842f9001f..670933add 100644 --- a/lib/directive/module.dart +++ b/lib/directive/module.dart @@ -5,7 +5,6 @@ * This package is imported for you as part of [angular.dart](#angular/angular), * and lists all of the basic directives that are part of Angular. * -* */ library angular.directive; @@ -69,8 +68,8 @@ class NgDirectiveModule extends Module { value(ContentEditableDirective, null); value(NgModel, null); value(NgValue, new NgValue(null)); - value(NgTrueValue, new NgTrueValue(null)); - value(NgFalseValue, new NgFalseValue(null)); + value(NgTrueValue, new NgTrueValue()); + value(NgFalseValue, new NgFalseValue()); value(NgSwitchDirective, null); value(NgSwitchWhenDirective, null); value(NgSwitchDefaultDirective, null); diff --git a/lib/directive/ng_model.dart b/lib/directive/ng_model.dart index 38d054500..5f7deb4fe 100644 --- a/lib/directive/ng_model.dart +++ b/lib/directive/ng_model.dart @@ -265,17 +265,32 @@ class NgModel extends NgControl implements NgAttachAware { /** * Usage: * - * + * * - * This creates a two way databinding between the boolean expression specified - * in ng-model and the checkbox input element in the DOM.  If the ng-model value - * is falsy (i.e. one of `false`, `null`, and `0`), then the checkbox is - * unchecked. Otherwise, it is checked.  Likewise, when the checkbox is checked, - * the model value is set to true. When unchecked, it is set to false. + * This creates a two way databinding between the `ng-model` expression + * and the checkbox input element state. + * + * If the optional `ng-true-value` is absent then: if the model expression + * evaluates to true or to a nonzero [num], then the checkbox is checked; + * otherwise, it is unchecked. + * + * If `ng-true-value="t_expr"` is present, then: if the model expression + * evaluates to the same value as `t_expr` then the checkbox is checked; + * otherwise, it is unchecked. + * + * When the checkbox is checked, the model is set to the value of `t_expr` if + * present, true otherwise. When unchecked, it is set to the value of + * `f_expr` if present, false otherwise. + * + * Also see [NgTrueValue] and [NgFalseValue]. */ @NgDirective(selector: 'input[type=checkbox][ng-model]') class InputCheckboxDirective { - final dom.InputElement inputElement; + final dom.CheckboxInputElement inputElement; final NgModel ngModel; final NgTrueValue ngTrueValue; final NgFalseValue ngFalseValue; @@ -285,14 +300,13 @@ class InputCheckboxDirective { this.scope, this.ngTrueValue, this.ngFalseValue) { ngModel.render = (value) { scope.rootScope.domWrite(() { - inputElement.checked = ngTrueValue.isValue(inputElement, value); + inputElement.checked = ngTrueValue.isValue(value); }); }; inputElement - ..onChange.listen((value) { + ..onChange.listen((_) { ngModel.viewValue = inputElement.checked - ? ngTrueValue.readValue(inputElement) - : ngFalseValue.readValue(inputElement); + ? ngTrueValue.value : ngFalseValue.value; }) ..onBlur.listen((e) { ngModel.markAsTouched(); @@ -473,44 +487,45 @@ class NgValue { } /** - * `ng-true-value` allows you to select any expression to be set to - * `ng-model` when checkbox is selected on ``. + * Usage: + * + * + * + * The initial value of the expression bound to this directive is assigned to + * the model when the input is checked. Note that the expression can be of any + * type, not just [String]. Also see [InputCheckboxDirective], [NgFalseValue]. */ -@NgDirective(selector: '[ng-true-value]') +@NgDirective(selector: 'input[type=checkbox][ng-model][ng-true-value]') class NgTrueValue { final dom.Element element; @NgOneWay('ng-true-value') - var value; - - NgTrueValue(this.element); + var value = true; - readValue(dom.Element element) { - assert(this.element == null || element == this.element); - return this.element == null ? true : value; - } + NgTrueValue([this.element]); - bool isValue(dom.Element element, value) { - assert(this.element == null || element == this.element); - return this.element == null ? toBool(value) : value == this.value; - } + bool isValue(val) => element == null ? toBool(val) : val == value; } /** - * `ng-false-value` allows you to select any expression to be set to - * `ng-model` when checkbox is deselected `. + * Usage: + * + * + * + * The initial value of the expression bound to this directive is assigned to + * the model when the input is unchecked. Note that the expression can be of any + * type, not just [String]. Also see [InputCheckboxDirective], [NgTrueValue]. */ -@NgDirective(selector: '[ng-false-value]') +@NgDirective(selector: 'input[type=checkbox][ng-model][ng-false-value]') class NgFalseValue { final dom.Element element; @NgOneWay('ng-false-value') - var value; - - NgFalseValue(this.element); + var value = false; - readValue(dom.Element element) { - assert(this.element == null || element == this.element); - return this.element == null ? false : value; - } + NgFalseValue([this.element]); } /** diff --git a/test/directive/ng_model_spec.dart b/test/directive/ng_model_spec.dart index e16060dc8..d3d069b85 100644 --- a/test/directive/ng_model_spec.dart +++ b/test/directive/ng_model_spec.dart @@ -631,7 +631,6 @@ void main() { expect(model.dirty).toEqual(true); }); - it('should update input value from model using ng-true-value/false', (Scope scope) { var element = _.compile(''); @@ -654,7 +653,6 @@ void main() { expect(scope.context['model']).toBe(0); }); - it('should allow non boolean values like null, 0, 1', (Scope scope) { var element = _.compile(''); @@ -674,7 +672,6 @@ void main() { expect(element.checked).toBe(false); }); - it('should update model from the input value', (Scope scope) { var element = _.compile(''); @@ -687,6 +684,23 @@ void main() { expect(scope.context['model']).toBe(false); }); + it('should update model from the input using ng-true-value/false', (Scope scope) { + var element = _.compile(''); + scope.apply(() { + scope.context['yes'] = 'yes sir!'; + scope.context['no'] = 'no, sorry'; + }); + + element.checked = true; + _.triggerEvent(element, 'change'); + expect(scope.context['model']).toEqual('yes sir!'); + + element.checked = false; + _.triggerEvent(element, 'change'); + expect(scope.context['model']).toEqual('no, sorry'); + }); + it('should only render the input value upon the next digest', (Scope scope) { _.compile(''); Probe probe = _.rootScope.context['p'];