diff --git a/modules/@angular/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts b/modules/@angular/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts new file mode 100644 index 0000000000..fbb73bdd0b --- /dev/null +++ b/modules/@angular/examples/forms/ts/nestedFormArray/e2e_test/nested_form_array_spec.ts @@ -0,0 +1,42 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {verifyNoBrowserErrors} from '../../../../_common/e2e_util'; + +describe('nestedFormArray example', () => { + afterEach(verifyNoBrowserErrors); + let inputs: ElementFinder; + let buttons: ElementFinder; + + beforeEach(() => { + browser.get('/forms/ts/nestedFormArray/index.html'); + inputs = element.all(by.css('input')); + buttons = element.all(by.css('button')); + }); + + it('should populate the UI with initial values', () => { + expect(inputs.get(0).getAttribute('value')).toEqual('SF'); + expect(inputs.get(1).getAttribute('value')).toEqual('NY'); + }); + + it('should add inputs programmatically', () => { + expect(browser.isElementPresent(inputs.get(2))).toBe(false); + + buttons.get(1).click(); + inputs = element.all(by.css('input')); + + expect(browser.isElementPresent(inputs.get(2))).toBe(true); + }); + + it('should set the value programmatically', () => { + buttons.get(2).click(); + expect(inputs.get(0).getAttribute('value')).toEqual('LA'); + expect(inputs.get(1).getAttribute('value')).toEqual('MTV'); + }); + +}); diff --git a/modules/@angular/examples/forms/ts/nestedFormArray/module.ts b/modules/@angular/examples/forms/ts/nestedFormArray/module.ts new file mode 100644 index 0000000000..eb2478a6e4 --- /dev/null +++ b/modules/@angular/examples/forms/ts/nestedFormArray/module.ts @@ -0,0 +1,20 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +import {NgModule} from '@angular/core'; +import {ReactiveFormsModule} from '@angular/forms'; +import {BrowserModule} from '@angular/platform-browser'; +import {NestedFormArray} from './nested_form_array_example'; + +@NgModule({ + imports: [BrowserModule, ReactiveFormsModule], + declarations: [NestedFormArray], + bootstrap: [NestedFormArray] +}) +export class AppModule { +} diff --git a/modules/@angular/examples/forms/ts/nestedFormArray/nested_form_array_example.ts b/modules/@angular/examples/forms/ts/nestedFormArray/nested_form_array_example.ts new file mode 100644 index 0000000000..02fe72ec23 --- /dev/null +++ b/modules/@angular/examples/forms/ts/nestedFormArray/nested_form_array_example.ts @@ -0,0 +1,48 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +// #docregion Component +import {Component} from '@angular/core'; +import {AbstractControl, FormArray, FormControl, FormGroup} from '@angular/forms'; + +@Component({ + selector: 'example-app', + template: ` +
+
+
+ +
+
+ +
+ + + + `, +}) +export class NestedFormArray { + form = new FormGroup({ + cities: new FormArray([ + new FormControl('SF'), + new FormControl('NY'), + ]), + }); + + get cities(): FormArray { return this.form.get('cities'); } + + addCity() { this.cities.push(new FormControl()); } + + onSubmit() { + console.log(this.cities.value); // ['SF', 'NY'] + console.log(this.form.value); // { cities: ['SF', 'NY'] } + } + + setPreset() { this.cities.patchValue(['LA', 'MTV']); } +} +// #enddocregion diff --git a/modules/@angular/forms/src/directives/reactive_directives/form_group_name.ts b/modules/@angular/forms/src/directives/reactive_directives/form_group_name.ts index 4107cb3206..3dca7c5a4c 100644 --- a/modules/@angular/forms/src/directives/reactive_directives/form_group_name.ts +++ b/modules/@angular/forms/src/directives/reactive_directives/form_group_name.ts @@ -95,38 +95,49 @@ export const formArrayNameProvider: any = { }; /** - * Syncs an existing form array to a DOM element. + * @whatItDoes Syncs a nested {@link FormArray} to a DOM element. * - * This directive can only be used as a child of {@link FormGroupDirective}. It also requires - * importing the {@link ReactiveFormsModule}. + * @howToUse * - * ```typescript - * @Component({ - * selector: 'my-app', - * template: ` - *
- *

Angular FormArray Example

- *
- *
- *
- * - *
- *
- *
- * {{ myForm.value | json }} // {cities: ['SF', 'NY']} - *
- * ` - * }) - * export class App { - * cityArray = new FormArray([ - * new FormControl('SF'), - * new FormControl('NY') - * ]); - * myForm = new FormGroup({ - * cities: this.cityArray - * }); - * } - * ``` + * This directive is designed to be used with a parent {@link FormGroupDirective} (selector: + * `[formGroup]`). + * + * It accepts the string name of the nested {@link FormArray} you want to link, and + * will look for a {@link FormArray} registered with that name in the parent + * {@link FormGroup} instance you passed into {@link FormGroupDirective}. + * + * Nested form arrays can come in handy when you have a group of form controls but + * you're not sure how many there will be. Form arrays allow you to create new + * form controls dynamically. + * + * **Access the array**: You can access the associated {@link FormArray} using the + * {@link AbstractControl.get} method on the parent {@link FormGroup}. + * Ex: `this.form.get('cities')`. + * + * **Get the value**: the `value` property is always synced and available on the + * {@link FormArray}. See a full list of available properties in {@link AbstractControl}. + * + * **Set the value**: You can set an initial value for each child control when instantiating + * the {@link FormArray}, or you can set the value programmatically later using the + * {@link FormArray}'s {@link AbstractControl.setValue} or {@link AbstractControl.patchValue} + * methods. + * + * **Listen to value**: If you want to listen to changes in the value of the array, you can + * subscribe to the {@link FormArray}'s {@link AbstractControl.valueChanges} event. You can also + * listen to its {@link AbstractControl.statusChanges} event to be notified when the validation + * status is re-calculated. + * + * **Add new controls**: You can add new controls to the {@link FormArray} dynamically by + * calling its {@link FormArray.push} method. + * Ex: `this.form.get('cities').push(new FormControl());` + * + * ### Example + * + * {@example forms/ts/nestedFormArray/nested_form_array_example.ts region='Component'} + * + * * **npm package**: `@angular/forms` + * + * * **NgModule**: `ReactiveFormsModule` * * @stable */