diff --git a/lib/directive/ng_control.dart b/lib/directive/ng_control.dart index b2b9b1f59..31bbc83c9 100644 --- a/lib/directive/ng_control.dart +++ b/lib/directive/ng_control.dart @@ -26,7 +26,7 @@ abstract class NgControl implements NgDetachAware { final Map> errors = new Map>(); final List _controls = new List(); - final Map _controlByName = new Map(); + final Map> _controlByName = new Map>(); NgControl(Scope this._scope, dom.Element this._element, Injector injector, NgAnimate this._animate) @@ -144,7 +144,7 @@ abstract class NgControl implements NgDetachAware { addControl(NgControl control) { _controls.add(control); if (control.name != null) { - _controlByName[control.name] = control; + _controlByName.putIfAbsent(control.name, () => new List()).add(control); } } @@ -157,8 +157,12 @@ abstract class NgControl implements NgDetachAware { */ removeControl(NgControl control) { _controls.remove(control); - if (control.name != null) { - _controlByName.remove(control.name); + String key = control.name; + if (key != null && _controlByName.containsKey(key)) { + _controlByName[key].remove(control); + if (_controlByName[key].isEmpty) { + _controlByName.remove(key); + } } } diff --git a/lib/directive/ng_form.dart b/lib/directive/ng_form.dart index 453f5f056..786365aaa 100644 --- a/lib/directive/ng_form.dart +++ b/lib/directive/ng_form.dart @@ -21,7 +21,7 @@ part of angular.directive; selector: '[ng-form]', publishTypes : const [NgControl], visibility: NgDirective.CHILDREN_VISIBILITY) -class NgForm extends NgControl implements Map { +class NgForm extends NgControl { /** * Instantiates a new instance of NgForm. Upon creation, the instance of the * class will be bound to the formName property on the scope (where formName @@ -54,56 +54,18 @@ class NgForm extends NgControl implements Map { _scope.context[name] = this; } - //FIXME: fix this reflection bug that shows up when Map is implemented - operator []=(String key, value) { - if (key == 'name') { - name = value; - } else { - _controlByName[key] = value; - } - } + get controls => _controlByName; - //FIXME: fix this reflection bug that shows up when Map is implemented - operator[](name) { - if (name == 'valid') { - return valid; - } else if (name == 'invalid') { - return invalid; - } else { - return _controlByName[name]; + NgControl operator[](name) { + if (controls.containsKey(name)) { + return controls[name][0]; } } - - bool get isEmpty => false; - bool get isNotEmpty => !isEmpty; - get values => null; - get keys => null; - get length => null; - clear() => null; - remove(_) => null; - containsKey(_) => false; - containsValue(_) => false; - addAll(_) => null; - forEach(_) => null; - putIfAbsent(_, __) => null; } class NgNullForm extends NgNullControl implements NgForm { NgNullForm() {} - operator[](name) {} - operator []=(String name, value) {} - bool get isEmpty => false; - bool get isNotEmpty => true; - get values => null; - get keys => null; - get length => null; - clear() => null; - remove(_) => null; - containsKey(_) => false; - containsValue(_) => false; - addAll(_) => null; - forEach(_) => null; - putIfAbsent(_, __) => null; + get controls => null; } diff --git a/test/directive/ng_form_spec.dart b/test/directive/ng_form_spec.dart index df8187c30..a23a32e8d 100644 --- a/test/directive/ng_form_spec.dart +++ b/test/directive/ng_form_spec.dart @@ -20,6 +20,50 @@ void main() { expect(form.name).toEqual('myForm'); })); + it('should return the first control with the given name when accessed using map notation', + inject((Scope scope, TestBed _) { + + var element = $('
' + + ' ' + + ' ' + + '
'); + + _.compile(element); + scope.apply(); + + NgForm form = _.rootScope.context['myForm']; + NgModel one = _.rootScope.context['a'].directive(NgModel); + NgModel two = _.rootScope.context['b'].directive(NgModel); + + expect(one).not.toBe(two); + expect(form['model']).toBe(one); + expect(scope.eval("myForm['model']")).toBe(one); + })); + + it('should return the all the controls with the given name', inject((Scope scope, TestBed _) { + var element = $('
' + + ' ' + + ' ' + + '
'); + + _.compile(element); + scope.apply(); + + NgForm form = _.rootScope.context['myForm']; + NgModel one = _.rootScope.context['a'].directive(NgModel); + NgModel two = _.rootScope.context['b'].directive(NgModel); + + expect(one).not.toBe(two); + + var controls = form.controls['model']; + expect(controls[0]).toBe(one); + expect(controls[1]).toBe(two); + + expect(scope.eval("myForm.controls['model'][0]")).toBe(one); + expect(scope.eval("myForm.controls['model'][1]")).toBe(two); + })); + + describe('pristine / dirty', () { it('should be set to pristine by default', inject((Scope scope, TestBed _) { var element = $('
'); @@ -462,6 +506,24 @@ void main() { })); }); + it("should use map notation to fetch controls", inject((TestBed _) { + Scope s = _.rootScope; + s.context['name'] = 'cool'; + + var form = _.compile('
' + + ' ' + + '
'); + + NgForm formModel = s.context['myForm']; + Probe probe = s.context['i']; + var model = probe.directive(NgModel); + + expect(s.eval('name')).toEqual('cool'); + expect(s.eval('myForm.name')).toEqual('myForm'); + expect(s.eval('myForm["name"]')).toBe(model); + expect(s.eval('myForm["name"].name')).toEqual("name"); + })); + describe('regression tests: form', () { it('should be resolvable by injector if configured by user.', () { module((Module module) {