From 30db7f5850a4bfbd63d646f5f57950409ddbed54 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Fri, 15 Jun 2018 17:29:30 +0200 Subject: [PATCH 1/3] feat(form.FormController): add $getControls() Fixes #14749 Closes #14517 Closes #13202 --- src/ng/directive/form.js | 23 ++++++++++++++++++++++ test/ng/directive/formSpec.js | 36 +++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/src/ng/directive/form.js b/src/ng/directive/form.js index 2677921c0d74..1d4af021e59e 100644 --- a/src/ng/directive/form.js +++ b/src/ng/directive/form.js @@ -4,6 +4,7 @@ */ var nullFormCtrl = { $addControl: noop, + $getControls: noop, $$renameControl: nullFormRenameControl, $removeControl: noop, $setValidity: noop, @@ -159,6 +160,28 @@ FormController.prototype = { control.$$parentForm = this; }, + /** + * @ngdoc method + * @name form.FormController#$getControls + * @returns {Array} the controls that are currently part of this form + * + * @description + * This method returns a **shallow copy** of the controls that are currently part of this form + * ({@link form.FormController `FormController`} / + * {@link ngModel.NgModelController `NgModelController`}) . This can be used + * for example to iterate over all controls to validate them. + * + * The controls can be accessed normally, but adding or removing controls from the array has no + * effect on the form. Instead, use {@link form.FormController#$addControl `$addControl()`} and + * {@link form.FormController#$removeControl `$removeControl()`}. + * Likewise, adding a control to / removing a control from the form is not reflected + * in the shallow copy. That means you should get a fresh copy from `$getControls` every time + * you need access to the controls. + */ + $getControls: function() { + return shallowCopy(this.$$controls); + }, + // Private API: rename a form control $$renameControl: function(control, newName) { var oldName = control.$name; diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js index 2d996bb359e1..490856efafb4 100644 --- a/test/ng/directive/formSpec.js +++ b/test/ng/directive/formSpec.js @@ -1200,6 +1200,42 @@ describe('form', function() { }); }); + fdescribe('$getControls', function() { + it('should return a shallow copy of the form controls', function() { + doc = $compile( + '
' + + '' + + '
' + + '' + + '
' + + '
')(scope); + + scope.$digest(); + + var form = doc, + formCtrl = scope.testForm, + formInput = form.children('input').eq(0), + formInputCtrl = formInput.controller('ngModel'), + nestedForm = form.find('div'), + nestedFormCtrl = nestedForm.controller('form'), + nestedInput = nestedForm.children('input').eq(0), + nestedInputCtrl = nestedInput.controller('ngModel'); + + var controls = formCtrl.$getControls(); + + expect(controls).not.toBe(formCtrl.$$controls); + + controls.push('something'); + expect(formCtrl.$$controls).not.toContain('something'); + + expect(controls[0]).toBe(formInputCtrl); + expect(controls[1]).toBe(nestedFormCtrl); + + var nestedControls = controls[1].$getControls(); + + expect(nestedControls[0]).toBe(nestedInputCtrl); + }); + }); it('should rename nested form controls when interpolated name changes', function() { scope.idA = 'A'; From ab8f14af35ea4cf4598a4c99e26eda506049faa7 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Sun, 17 Jun 2018 21:09:09 +0200 Subject: [PATCH 2/3] fixup! feat(form.FormController): add $getControls() --- src/ng/directive/form.js | 22 ++++++++++++---------- test/ng/directive/formSpec.js | 13 ++++++++++++- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/ng/directive/form.js b/src/ng/directive/form.js index 1d4af021e59e..fe03a7af4a34 100644 --- a/src/ng/directive/form.js +++ b/src/ng/directive/form.js @@ -4,7 +4,7 @@ */ var nullFormCtrl = { $addControl: noop, - $getControls: noop, + $getControls: valueFn([]), $$renameControl: nullFormRenameControl, $removeControl: noop, $setValidity: noop, @@ -166,16 +166,18 @@ FormController.prototype = { * @returns {Array} the controls that are currently part of this form * * @description - * This method returns a **shallow copy** of the controls that are currently part of this form - * ({@link form.FormController `FormController`} / - * {@link ngModel.NgModelController `NgModelController`}) . This can be used - * for example to iterate over all controls to validate them. + * This method returns a **shallow copy** of the controls that are currently part of this form. + * The controls can be instances of {@link form.FormController `FormController`} + * ({@link ngForm "child-forms"}) and of {@link ngModel.NgModelController `NgModelController`}. + * If you need access to the controls of child-forms, you have to call `$getControls()` + * recursively on them. + * This can be used for example to iterate over all controls to validate them. * - * The controls can be accessed normally, but adding or removing controls from the array has no - * effect on the form. Instead, use {@link form.FormController#$addControl `$addControl()`} and - * {@link form.FormController#$removeControl `$removeControl()`}. - * Likewise, adding a control to / removing a control from the form is not reflected - * in the shallow copy. That means you should get a fresh copy from `$getControls` every time + * The controls can be accessed normally, but adding to, or removing controls from the array has + * no effect on the form. Instead, use {@link form.FormController#$addControl `$addControl()`} and + * {@link form.FormController#$removeControl `$removeControl()`} for this use-case. + * Likewise, adding a control to, or removing a control from the form is not reflected + * in the shallow copy. That means you should get a fresh copy from `$getControls()` every time * you need access to the controls. */ $getControls: function() { diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js index 490856efafb4..98caef4e8083 100644 --- a/test/ng/directive/formSpec.js +++ b/test/ng/directive/formSpec.js @@ -1200,7 +1200,18 @@ describe('form', function() { }); }); - fdescribe('$getControls', function() { + describe('$getControls', function() { + it('should return an empty array if the controller has no controls', function() { + doc = $compile('
')(scope); + + scope.$digest(); + + var form = doc, + formCtrl = scope.testForm; + + expect(formCtrl.$getControls()).toEqual([]); + }); + it('should return a shallow copy of the form controls', function() { doc = $compile( '
' + From 22775efd3d61c5dae9a4f28cb467d53348dbc180 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Mon, 18 Jun 2018 16:01:32 +0200 Subject: [PATCH 3/3] remove unused variable --- test/ng/directive/formSpec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js index 98caef4e8083..42044dd207f4 100644 --- a/test/ng/directive/formSpec.js +++ b/test/ng/directive/formSpec.js @@ -1206,8 +1206,7 @@ describe('form', function() { scope.$digest(); - var form = doc, - formCtrl = scope.testForm; + var formCtrl = scope.testForm; expect(formCtrl.$getControls()).toEqual([]); });