Skip to content

Commit

Permalink
fix(forms): allow arrays as parents (#10440)
Browse files Browse the repository at this point in the history
Closes #10432
  • Loading branch information
kara authored Aug 2, 2016
1 parent a55d796 commit d6d4568
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 142 deletions.
6 changes: 2 additions & 4 deletions modules/@angular/forms/src/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@ import {NgModel} from './directives/ng_model';
import {NgModelGroup} from './directives/ng_model_group';
import {NumberValueAccessor} from './directives/number_value_accessor';
import {RadioControlValueAccessor} from './directives/radio_control_value_accessor';
import {FormArrayName} from './directives/reactive_directives/form_array_name';
import {FormControlDirective} from './directives/reactive_directives/form_control_directive';
import {FormControlName} from './directives/reactive_directives/form_control_name';
import {FormGroupDirective} from './directives/reactive_directives/form_group_directive';
import {FormGroupName} from './directives/reactive_directives/form_group_name';
import {FormArrayName, FormGroupName} from './directives/reactive_directives/form_group_name';
import {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
import {NgSelectMultipleOption, SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
import {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator} from './directives/validators';
Expand All @@ -35,11 +34,10 @@ export {NgModel} from './directives/ng_model';
export {NgModelGroup} from './directives/ng_model_group';
export {NumberValueAccessor} from './directives/number_value_accessor';
export {RadioControlValueAccessor} from './directives/radio_control_value_accessor';
export {FormArrayName} from './directives/reactive_directives/form_array_name';
export {FormControlDirective} from './directives/reactive_directives/form_control_directive';
export {FormControlName} from './directives/reactive_directives/form_control_name';
export {FormGroupDirective} from './directives/reactive_directives/form_group_directive';
export {FormGroupName} from './directives/reactive_directives/form_group_name';
export {FormArrayName, FormGroupName} from './directives/reactive_directives/form_group_name';
export {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
export {NgSelectMultipleOption, SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator} from './directives/validators';
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import {Directive, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, SkipSelf, forwardRef} from '@angular/core';

import {EventEmitter, ObservableWrapper} from '../../facade/async';
import {BaseException} from '../../facade/exceptions';
import {FormControl} from '../../model';
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
import {AbstractFormGroupDirective} from '../abstract_form_group_directive';
Expand All @@ -20,10 +19,8 @@ import {ReactiveErrors} from '../reactive_errors';
import {composeAsyncValidators, composeValidators, controlPath, isPropertyUpdated, selectValueAccessor} from '../shared';
import {AsyncValidatorFn, ValidatorFn} from '../validators';

import {FormArrayName} from './form_array_name';
import {FormGroupDirective} from './form_group_directive';
import {FormGroupName} from './form_group_name';

import {FormArrayName, FormGroupName} from './form_group_name';

export const controlNameBinding: any = {
provide: NgControl,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import {NgControl} from '../ng_control';
import {ReactiveErrors} from '../reactive_errors';
import {composeAsyncValidators, composeValidators, setUpControl, setUpFormContainer} from '../shared';

import {FormArrayName} from './form_array_name';
import {FormGroupName} from './form_group_name';
import {FormArrayName, FormGroupName} from './form_group_name';

export const formDirectiveProvider: any = {
provide: ControlContainer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@

import {Directive, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core';

import {BaseException} from '../../facade/exceptions';
import {FormArray} from '../../model';
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
import {AbstractFormGroupDirective} from '../abstract_form_group_directive';
import {ControlContainer} from '../control_container';
import {ReactiveErrors} from '../reactive_errors';
import {composeAsyncValidators, composeValidators, controlPath} from '../shared';
import {AsyncValidatorFn, ValidatorFn} from '../validators';

import {FormGroupDirective} from './form_group_directive';

Expand Down Expand Up @@ -85,8 +87,100 @@ export class FormGroupName extends AbstractFormGroupDirective implements OnInit,

/** @internal */
_checkParentType(): void {
if (!(this._parent instanceof FormGroupName) && !(this._parent instanceof FormGroupDirective)) {
if (_hasInvalidParent(this._parent)) {
ReactiveErrors.groupParentException();
}
}
}

export const formArrayNameProvider: any = {
provide: ControlContainer,
useExisting: forwardRef(() => FormArrayName)
};

/**
* Syncs an existing form array to a DOM element.
*
* This directive can only be used as a child of {@link FormGroupDirective}.
*
* ```typescript
* @Component({
* selector: 'my-app',
* template: `
* <div>
* <h2>Angular FormArray Example</h2>
* <form [formGroup]="myForm">
* <div formArrayName="cities">
* <div *ngFor="let city of cityArray.controls; let i=index">
* <input [formControlName]="i">
* </div>
* </div>
* </form>
* {{ myForm.value | json }} // {cities: ['SF', 'NY']}
* </div>
* `
* })
* export class App {
* cityArray = new FormArray([
* new FormControl('SF'),
* new FormControl('NY')
* ]);
* myForm = new FormGroup({
* cities: this.cityArray
* });
* }
* ```
*
* @experimental
*/
@Directive({selector: '[formArrayName]', providers: [formArrayNameProvider]})
export class FormArrayName extends ControlContainer implements OnInit, OnDestroy {
/** @internal */
_parent: ControlContainer;

/** @internal */
_validators: any[];

/** @internal */
_asyncValidators: any[];

@Input('formArrayName') name: string;

constructor(
@Optional() @Host() @SkipSelf() parent: ControlContainer,
@Optional() @Self() @Inject(NG_VALIDATORS) validators: any[],
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) asyncValidators: any[]) {
super();
this._parent = parent;
this._validators = validators;
this._asyncValidators = asyncValidators;
}

ngOnInit(): void {
this._checkParentType();
this.formDirective.addFormArray(this);
}

ngOnDestroy(): void { this.formDirective.removeFormArray(this); }

get control(): FormArray { return this.formDirective.getFormArray(this); }

get formDirective(): FormGroupDirective { return <FormGroupDirective>this._parent.formDirective; }

get path(): string[] { return controlPath(this.name, this._parent); }

get validator(): ValidatorFn { return composeValidators(this._validators); }

get asyncValidator(): AsyncValidatorFn { return composeAsyncValidators(this._asyncValidators); }

private _checkParentType(): void {
if (_hasInvalidParent(this._parent)) {
ReactiveErrors.arrayParentException();
}
}
}

function _hasInvalidParent(parent: ControlContainer): boolean {
return !(parent instanceof FormGroupName) && !(parent instanceof FormGroupDirective) &&
!(parent instanceof FormArrayName);
}
3 changes: 2 additions & 1 deletion modules/@angular/forms/src/directives/reactive_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
*/

import {BaseException} from '../facade/exceptions';

import {FormErrorExamples as Examples} from './error_examples';

export class ReactiveErrors {
Expand Down Expand Up @@ -60,4 +61,4 @@ export class ReactiveErrors {
${Examples.formArrayName}`);
}
}
}
2 changes: 1 addition & 1 deletion modules/@angular/forms/src/directives/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {NgControl} from './ng_control';
import {normalizeAsyncValidator, normalizeValidator} from './normalize_validator';
import {NumberValueAccessor} from './number_value_accessor';
import {RadioControlValueAccessor} from './radio_control_value_accessor';
import {FormArrayName} from './reactive_directives/form_array_name';
import {FormArrayName} from './reactive_directives/form_group_name';
import {SelectControlValueAccessor} from './select_control_value_accessor';
import {SelectMultipleControlValueAccessor} from './select_multiple_control_value_accessor';
import {AsyncValidatorFn, ValidatorFn} from './validators';
Expand Down
2 changes: 1 addition & 1 deletion modules/@angular/forms/src/forms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ export {NgControlStatus} from './directives/ng_control_status';
export {NgForm} from './directives/ng_form';
export {NgModel} from './directives/ng_model';
export {NgModelGroup} from './directives/ng_model_group';
export {FormArrayName} from './directives/reactive_directives/form_array_name';
export {FormControlDirective} from './directives/reactive_directives/form_control_directive';
export {FormControlName} from './directives/reactive_directives/form_control_name';
export {FormGroupDirective} from './directives/reactive_directives/form_group_directive';
export {FormArrayName} from './directives/reactive_directives/form_group_name';
export {FormGroupName} from './directives/reactive_directives/form_group_name';
export {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
export {SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
Expand Down
Loading

0 comments on commit d6d4568

Please sign in to comment.