fix(forms): separate ngModelGroup from formGroupName
This commit is contained in:
parent
bc888bf3a1
commit
5c0cfdee48
|
@ -22,15 +22,16 @@ export {CheckboxControlValueAccessor} from './forms/directives/checkbox_value_ac
|
||||||
export {ControlContainer} from './forms/directives/control_container';
|
export {ControlContainer} from './forms/directives/control_container';
|
||||||
export {ControlValueAccessor, NG_VALUE_ACCESSOR} from './forms/directives/control_value_accessor';
|
export {ControlValueAccessor, NG_VALUE_ACCESSOR} from './forms/directives/control_value_accessor';
|
||||||
export {DefaultValueAccessor} from './forms/directives/default_value_accessor';
|
export {DefaultValueAccessor} from './forms/directives/default_value_accessor';
|
||||||
export {FormControlName} from './forms/directives/form_control_name';
|
|
||||||
export {Form} from './forms/directives/form_interface';
|
export {Form} from './forms/directives/form_interface';
|
||||||
export {NgControl} from './forms/directives/ng_control';
|
export {NgControl} from './forms/directives/ng_control';
|
||||||
export {NgControlGroup} from './forms/directives/ng_control_group';
|
|
||||||
export {NgControlStatus} from './forms/directives/ng_control_status';
|
export {NgControlStatus} from './forms/directives/ng_control_status';
|
||||||
export {NgForm} from './forms/directives/ng_form';
|
export {NgForm} from './forms/directives/ng_form';
|
||||||
export {NgModel} from './forms/directives/ng_model';
|
export {NgModel} from './forms/directives/ng_model';
|
||||||
|
export {NgModelGroup} from './forms/directives/ng_model_group';
|
||||||
export {FormControlDirective} from './forms/directives/reactive_directives/form_control_directive';
|
export {FormControlDirective} from './forms/directives/reactive_directives/form_control_directive';
|
||||||
|
export {FormControlName} from './forms/directives/reactive_directives/form_control_name';
|
||||||
export {FormGroupDirective} from './forms/directives/reactive_directives/form_group_directive';
|
export {FormGroupDirective} from './forms/directives/reactive_directives/form_group_directive';
|
||||||
|
export {FormGroupName} from './forms/directives/reactive_directives/form_group_name';
|
||||||
export {NgSelectOption, SelectControlValueAccessor} from './forms/directives/select_control_value_accessor';
|
export {NgSelectOption, SelectControlValueAccessor} from './forms/directives/select_control_value_accessor';
|
||||||
export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator, Validator} from './forms/directives/validators';
|
export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator, Validator} from './forms/directives/validators';
|
||||||
export {FormBuilder} from './forms/form_builder';
|
export {FormBuilder} from './forms/form_builder';
|
||||||
|
|
|
@ -2,15 +2,16 @@ import {Type} from '@angular/core';
|
||||||
|
|
||||||
import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
|
import {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
|
||||||
import {DefaultValueAccessor} from './directives/default_value_accessor';
|
import {DefaultValueAccessor} from './directives/default_value_accessor';
|
||||||
import {FormControlName} from './directives/form_control_name';
|
|
||||||
import {NgControlGroup} from './directives/ng_control_group';
|
|
||||||
import {NgControlStatus} from './directives/ng_control_status';
|
import {NgControlStatus} from './directives/ng_control_status';
|
||||||
import {NgForm} from './directives/ng_form';
|
import {NgForm} from './directives/ng_form';
|
||||||
import {NgModel} from './directives/ng_model';
|
import {NgModel} from './directives/ng_model';
|
||||||
|
import {NgModelGroup} from './directives/ng_model_group';
|
||||||
import {NumberValueAccessor} from './directives/number_value_accessor';
|
import {NumberValueAccessor} from './directives/number_value_accessor';
|
||||||
import {RadioControlValueAccessor} from './directives/radio_control_value_accessor';
|
import {RadioControlValueAccessor} from './directives/radio_control_value_accessor';
|
||||||
import {FormControlDirective} from './directives/reactive_directives/form_control_directive';
|
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 {FormGroupDirective} from './directives/reactive_directives/form_group_directive';
|
||||||
|
import {FormGroupName} from './directives/reactive_directives/form_group_name';
|
||||||
import {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
|
import {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
|
||||||
import {NgSelectMultipleOption, SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
|
import {NgSelectMultipleOption, SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
|
||||||
import {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator} from './directives/validators';
|
import {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator} from './directives/validators';
|
||||||
|
@ -18,16 +19,17 @@ import {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValida
|
||||||
export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
|
export {CheckboxControlValueAccessor} from './directives/checkbox_value_accessor';
|
||||||
export {ControlValueAccessor} from './directives/control_value_accessor';
|
export {ControlValueAccessor} from './directives/control_value_accessor';
|
||||||
export {DefaultValueAccessor} from './directives/default_value_accessor';
|
export {DefaultValueAccessor} from './directives/default_value_accessor';
|
||||||
export {FormControlName} from './directives/form_control_name';
|
|
||||||
export {NgControl} from './directives/ng_control';
|
export {NgControl} from './directives/ng_control';
|
||||||
export {NgControlGroup} from './directives/ng_control_group';
|
|
||||||
export {NgControlStatus} from './directives/ng_control_status';
|
export {NgControlStatus} from './directives/ng_control_status';
|
||||||
export {NgForm} from './directives/ng_form';
|
export {NgForm} from './directives/ng_form';
|
||||||
export {NgModel} from './directives/ng_model';
|
export {NgModel} from './directives/ng_model';
|
||||||
|
export {NgModelGroup} from './directives/ng_model_group';
|
||||||
export {NumberValueAccessor} from './directives/number_value_accessor';
|
export {NumberValueAccessor} from './directives/number_value_accessor';
|
||||||
export {RadioButtonState, RadioControlValueAccessor} from './directives/radio_control_value_accessor';
|
export {RadioButtonState, RadioControlValueAccessor} from './directives/radio_control_value_accessor';
|
||||||
export {FormControlDirective} from './directives/reactive_directives/form_control_directive';
|
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 {FormGroupDirective} from './directives/reactive_directives/form_group_directive';
|
||||||
|
export {FormGroupName} from './directives/reactive_directives/form_group_name';
|
||||||
export {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
|
export {NgSelectOption, SelectControlValueAccessor} from './directives/select_control_value_accessor';
|
||||||
export {NgSelectMultipleOption, SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
|
export {NgSelectMultipleOption, SelectMultipleControlValueAccessor} from './directives/select_multiple_control_value_accessor';
|
||||||
export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator} from './directives/validators';
|
export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValidator} from './directives/validators';
|
||||||
|
@ -52,9 +54,7 @@ export {MaxLengthValidator, MinLengthValidator, PatternValidator, RequiredValida
|
||||||
* @experimental
|
* @experimental
|
||||||
*/
|
*/
|
||||||
export const FORM_DIRECTIVES: Type[] = /*@ts2dart_const*/[
|
export const FORM_DIRECTIVES: Type[] = /*@ts2dart_const*/[
|
||||||
NgControlGroup,
|
NgModel, NgModelGroup, NgForm,
|
||||||
|
|
||||||
NgModel, NgForm,
|
|
||||||
|
|
||||||
NgSelectOption, NgSelectMultipleOption, DefaultValueAccessor, NumberValueAccessor,
|
NgSelectOption, NgSelectMultipleOption, DefaultValueAccessor, NumberValueAccessor,
|
||||||
CheckboxControlValueAccessor, SelectControlValueAccessor, SelectMultipleControlValueAccessor,
|
CheckboxControlValueAccessor, SelectControlValueAccessor, SelectMultipleControlValueAccessor,
|
||||||
|
@ -64,4 +64,4 @@ export const FORM_DIRECTIVES: Type[] = /*@ts2dart_const*/[
|
||||||
];
|
];
|
||||||
|
|
||||||
export const REACTIVE_FORM_DIRECTIVES: Type[] =
|
export const REACTIVE_FORM_DIRECTIVES: Type[] =
|
||||||
/*@ts2dart_const*/[FormControlDirective, FormGroupDirective, FormControlName];
|
/*@ts2dart_const*/[FormControlDirective, FormGroupDirective, FormControlName, FormGroupName];
|
|
@ -0,0 +1,46 @@
|
||||||
|
import {OnDestroy, OnInit} from '@angular/core';
|
||||||
|
|
||||||
|
import {FormGroup} from '../model';
|
||||||
|
|
||||||
|
import {ControlContainer} from './control_container';
|
||||||
|
import {Form} from './form_interface';
|
||||||
|
import {composeAsyncValidators, composeValidators, controlPath} from './shared';
|
||||||
|
import {AsyncValidatorFn, ValidatorFn} from './validators';
|
||||||
|
|
||||||
|
/**
|
||||||
|
This is a base class for code shared between {@link NgModelGroup} and {@link FormGroupName}.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export class AbstractFormGroupDirective extends ControlContainer implements OnInit, OnDestroy {
|
||||||
|
/** @internal */
|
||||||
|
_parent: ControlContainer;
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_validators: any[];
|
||||||
|
|
||||||
|
/** @internal */
|
||||||
|
_asyncValidators: any[];
|
||||||
|
|
||||||
|
ngOnInit(): void { this.formDirective.addFormGroup(this); }
|
||||||
|
|
||||||
|
ngOnDestroy(): void { this.formDirective.removeFormGroup(this); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link FormGroup} backing this binding.
|
||||||
|
*/
|
||||||
|
get control(): FormGroup { return this.formDirective.getFormGroup(this); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the path to this control group.
|
||||||
|
*/
|
||||||
|
get path(): string[] { return controlPath(this.name, this._parent); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link Form} to which this group belongs.
|
||||||
|
*/
|
||||||
|
get formDirective(): Form { return this._parent.formDirective; }
|
||||||
|
|
||||||
|
get validator(): ValidatorFn { return composeValidators(this._validators); }
|
||||||
|
|
||||||
|
get asyncValidator(): AsyncValidatorFn { return composeAsyncValidators(this._asyncValidators); }
|
||||||
|
}
|
|
@ -1,7 +1,8 @@
|
||||||
import {FormControl, FormGroup} from '../model';
|
import {FormControl, FormGroup} from '../model';
|
||||||
|
|
||||||
|
import {AbstractFormGroupDirective} from './abstract_form_group_directive';
|
||||||
import {NgControl} from './ng_control';
|
import {NgControl} from './ng_control';
|
||||||
import {NgControlGroup} from './ng_control_group';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,17 +31,17 @@ export interface Form {
|
||||||
/**
|
/**
|
||||||
* Add a group of controls to this form.
|
* Add a group of controls to this form.
|
||||||
*/
|
*/
|
||||||
addFormGroup(dir: NgControlGroup): void;
|
addFormGroup(dir: AbstractFormGroupDirective): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove a group of controls from this form.
|
* Remove a group of controls from this form.
|
||||||
*/
|
*/
|
||||||
removeFormGroup(dir: NgControlGroup): void;
|
removeFormGroup(dir: AbstractFormGroupDirective): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look up the {@link FormGroup} associated with a particular {@link NgControlGroup}.
|
* Look up the {@link FormGroup} associated with a particular {@link AbstractFormGroupDirective}.
|
||||||
*/
|
*/
|
||||||
getFormGroup(dir: NgControlGroup): FormGroup;
|
getFormGroup(dir: AbstractFormGroupDirective): FormGroup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the model for a particular control with a new value.
|
* Update the model for a particular control with a new value.
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
import {Directive, Host, Inject, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core';
|
|
||||||
|
|
||||||
import {FormGroup} from '../model';
|
|
||||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
|
|
||||||
|
|
||||||
import {ControlContainer} from './control_container';
|
|
||||||
import {Form} from './form_interface';
|
|
||||||
import {composeAsyncValidators, composeValidators, controlPath} from './shared';
|
|
||||||
import {AsyncValidatorFn, ValidatorFn} from './validators';
|
|
||||||
|
|
||||||
export const controlGroupProvider: any =
|
|
||||||
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
|
|
||||||
provide: ControlContainer,
|
|
||||||
useExisting: forwardRef(() => NgControlGroup)
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and binds a control group to a DOM element.
|
|
||||||
*
|
|
||||||
* This directive can only be used as a child of {@link NgForm} or {@link FormGroupDirective}.
|
|
||||||
*
|
|
||||||
* ```typescript
|
|
||||||
* @Component({
|
|
||||||
* selector: 'my-app',
|
|
||||||
* template: `
|
|
||||||
* <div>
|
|
||||||
* <h2>Angular FormControl & FormGroup Example</h2>
|
|
||||||
* <form #f="ngForm">
|
|
||||||
* <div ngControlGroup="name" #cgName="ngForm">
|
|
||||||
* <h3>Enter your name:</h3>
|
|
||||||
* <p>First: <input name="first" ngModel required></p>
|
|
||||||
* <p>Middle: <input name="middle" ngModel></p>
|
|
||||||
* <p>Last: <input name="last" ngModel required></p>
|
|
||||||
* </div>
|
|
||||||
* <h3>Name value:</h3>
|
|
||||||
* <pre>{{valueOf(cgName)}}</pre>
|
|
||||||
* <p>Name is {{cgName?.control?.valid ? "valid" : "invalid"}}</p>
|
|
||||||
* <h3>What's your favorite food?</h3>
|
|
||||||
* <p><input name="food" ngModel></p>
|
|
||||||
* <h3>Form value</h3>
|
|
||||||
* <pre>{{valueOf(f)}}</pre>
|
|
||||||
* </form>
|
|
||||||
* </div>
|
|
||||||
* `
|
|
||||||
* })
|
|
||||||
* export class App {
|
|
||||||
* valueOf(cg: NgControlGroup): string {
|
|
||||||
* if (cg.control == null) {
|
|
||||||
* return null;
|
|
||||||
* }
|
|
||||||
* return JSON.stringify(cg.control.value, null, 2);
|
|
||||||
* }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* This example declares a control group for a user's name. The value and validation state of
|
|
||||||
* this group can be accessed separately from the overall form.
|
|
||||||
*
|
|
||||||
* @experimental
|
|
||||||
*/
|
|
||||||
@Directive({
|
|
||||||
selector: '[ngControlGroup]',
|
|
||||||
providers: [controlGroupProvider],
|
|
||||||
inputs: ['name: ngControlGroup'],
|
|
||||||
exportAs: 'ngForm'
|
|
||||||
})
|
|
||||||
export class NgControlGroup extends ControlContainer implements OnInit,
|
|
||||||
OnDestroy {
|
|
||||||
/** @internal */
|
|
||||||
_parent: ControlContainer;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
@Host() @SkipSelf() parent: ControlContainer,
|
|
||||||
@Optional() @Self() @Inject(NG_VALIDATORS) private _validators: any[],
|
|
||||||
@Optional() @Self() @Inject(NG_ASYNC_VALIDATORS) private _asyncValidators: any[]) {
|
|
||||||
super();
|
|
||||||
this._parent = parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit(): void { this.formDirective.addFormGroup(this); }
|
|
||||||
|
|
||||||
ngOnDestroy(): void { this.formDirective.removeFormGroup(this); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the {@link FormGroup} backing this binding.
|
|
||||||
*/
|
|
||||||
get control(): FormGroup { return this.formDirective.getFormGroup(this); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the path to this control group.
|
|
||||||
*/
|
|
||||||
get path(): string[] { return controlPath(this.name, this._parent); }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the {@link Form} to which this group belongs.
|
|
||||||
*/
|
|
||||||
get formDirective(): Form { return this._parent.formDirective; }
|
|
||||||
|
|
||||||
get validator(): ValidatorFn { return composeValidators(this._validators); }
|
|
||||||
|
|
||||||
get asyncValidator(): AsyncValidatorFn { return composeAsyncValidators(this._asyncValidators); }
|
|
||||||
}
|
|
|
@ -9,7 +9,7 @@ import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
|
||||||
import {ControlContainer} from './control_container';
|
import {ControlContainer} from './control_container';
|
||||||
import {Form} from './form_interface';
|
import {Form} from './form_interface';
|
||||||
import {NgControl} from './ng_control';
|
import {NgControl} from './ng_control';
|
||||||
import {NgControlGroup} from './ng_control_group';
|
import {NgModelGroup} from './ng_model_group';
|
||||||
import {composeAsyncValidators, composeValidators, setUpControl, setUpFormGroup} from './shared';
|
import {composeAsyncValidators, composeValidators, setUpControl, setUpFormGroup} from './shared';
|
||||||
|
|
||||||
export const formDirectiveProvider: any =
|
export const formDirectiveProvider: any =
|
||||||
|
@ -44,12 +44,12 @@ export const formDirectiveProvider: any =
|
||||||
* <h2>NgForm demo</h2>
|
* <h2>NgForm demo</h2>
|
||||||
* <form #f="ngForm" (ngSubmit)="onSubmit(f.value)">
|
* <form #f="ngForm" (ngSubmit)="onSubmit(f.value)">
|
||||||
* <h3>Control group: credentials</h3>
|
* <h3>Control group: credentials</h3>
|
||||||
* <div ngControlGroup="credentials">
|
* <div ngModelGroup="credentials">
|
||||||
* <p>Login: <input type="text" name="login" ngModel></p>
|
* <p>Login: <input type="text" name="login" ngModel></p>
|
||||||
* <p>Password: <input type="password" name="password" ngModel></p>
|
* <p>Password: <input type="password" name="password" ngModel></p>
|
||||||
* </div>
|
* </div>
|
||||||
* <h3>Control group: person</h3>
|
* <h3>Control group: person</h3>
|
||||||
* <div ngControlGroup="person">
|
* <div ngModelGroup="person">
|
||||||
* <p>First name: <input type="text" name="firstName" ngModel></p>
|
* <p>First name: <input type="text" name="firstName" ngModel></p>
|
||||||
* <p>Last name: <input type="text" name="lastName" ngModel></p>
|
* <p>Last name: <input type="text" name="lastName" ngModel></p>
|
||||||
* </div>
|
* </div>
|
||||||
|
@ -129,7 +129,7 @@ export class NgForm extends ControlContainer implements Form {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
addFormGroup(dir: NgControlGroup): void {
|
addFormGroup(dir: NgModelGroup): void {
|
||||||
PromiseWrapper.scheduleMicrotask(() => {
|
PromiseWrapper.scheduleMicrotask(() => {
|
||||||
var container = this._findContainer(dir.path);
|
var container = this._findContainer(dir.path);
|
||||||
var group = new FormGroup({});
|
var group = new FormGroup({});
|
||||||
|
@ -139,7 +139,7 @@ export class NgForm extends ControlContainer implements Form {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFormGroup(dir: NgControlGroup): void {
|
removeFormGroup(dir: NgModelGroup): void {
|
||||||
PromiseWrapper.scheduleMicrotask(() => {
|
PromiseWrapper.scheduleMicrotask(() => {
|
||||||
var container = this._findContainer(dir.path);
|
var container = this._findContainer(dir.path);
|
||||||
if (isPresent(container)) {
|
if (isPresent(container)) {
|
||||||
|
@ -148,7 +148,7 @@ export class NgForm extends ControlContainer implements Form {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormGroup(dir: NgControlGroup): FormGroup { return <FormGroup>this.form.find(dir.path); }
|
getFormGroup(dir: NgModelGroup): FormGroup { return <FormGroup>this.form.find(dir.path); }
|
||||||
|
|
||||||
updateModel(dir: NgControl, value: any): void {
|
updateModel(dir: NgControl, value: any): void {
|
||||||
PromiseWrapper.scheduleMicrotask(() => {
|
PromiseWrapper.scheduleMicrotask(() => {
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import {Directive, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core';
|
||||||
|
|
||||||
|
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
|
||||||
|
|
||||||
|
import {AbstractFormGroupDirective} from './abstract_form_group_directive';
|
||||||
|
import {ControlContainer} from './control_container';
|
||||||
|
|
||||||
|
export const modelGroupProvider: any =
|
||||||
|
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
|
||||||
|
provide: ControlContainer,
|
||||||
|
useExisting: forwardRef(() => NgModelGroup)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates and binds a model group to a DOM element.
|
||||||
|
*
|
||||||
|
* This directive can only be used as a child of {@link NgForm}.
|
||||||
|
*
|
||||||
|
* ```typescript
|
||||||
|
* @Component({
|
||||||
|
* selector: 'my-app',
|
||||||
|
* template: `
|
||||||
|
* <div>
|
||||||
|
* <h2>Angular forms Example</h2>
|
||||||
|
* <form #f="ngForm">
|
||||||
|
* <div ngModelGroup="name" #mgName="ngModelGroup">
|
||||||
|
* <h3>Enter your name:</h3>
|
||||||
|
* <p>First: <input name="first" ngModel required></p>
|
||||||
|
* <p>Middle: <input name="middle" ngModel></p>
|
||||||
|
* <p>Last: <input name="last" ngModel required></p>
|
||||||
|
* </div>
|
||||||
|
* <h3>Name value:</h3>
|
||||||
|
* <pre>{{ mgName | json }}</pre>
|
||||||
|
* <p>Name is {{mgName?.valid ? "valid" : "invalid"}}</p>
|
||||||
|
* <h3>What's your favorite food?</h3>
|
||||||
|
* <p><input name="food" ngModel></p>
|
||||||
|
* <h3>Form value</h3>
|
||||||
|
* <pre>{{ f | json }}</pre>
|
||||||
|
* </form>
|
||||||
|
* </div>
|
||||||
|
* `
|
||||||
|
* })
|
||||||
|
* export class App {}
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This example declares a model group for a user's name. The value and validation state of
|
||||||
|
* this group can be accessed separately from the overall form.
|
||||||
|
*
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
@Directive({selector: '[ngModelGroup]', providers: [modelGroupProvider], exportAs: 'ngModelGroup'})
|
||||||
|
export class NgModelGroup extends AbstractFormGroupDirective implements OnInit, OnDestroy {
|
||||||
|
@Input('ngModelGroup') name: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,14 +1,14 @@
|
||||||
import {Directive, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, SkipSelf, forwardRef} from '@angular/core';
|
import {Directive, Host, Inject, Input, OnChanges, OnDestroy, Optional, Output, Self, SimpleChanges, SkipSelf, forwardRef} from '@angular/core';
|
||||||
|
|
||||||
import {EventEmitter, ObservableWrapper} from '../../facade/async';
|
import {EventEmitter, ObservableWrapper} from '../../../facade/async';
|
||||||
import {FormControl} from '../model';
|
import {FormControl} from '../../model';
|
||||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../validators';
|
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
|
||||||
|
|
||||||
import {ControlContainer} from './control_container';
|
import {ControlContainer} from '../control_container';
|
||||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from './control_value_accessor';
|
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '../control_value_accessor';
|
||||||
import {NgControl} from './ng_control';
|
import {NgControl} from '../ng_control';
|
||||||
import {composeAsyncValidators, composeValidators, controlPath, isPropertyUpdated, selectValueAccessor} from './shared';
|
import {composeAsyncValidators, composeValidators, controlPath, isPropertyUpdated, selectValueAccessor} from '../shared';
|
||||||
import {AsyncValidatorFn, ValidatorFn} from './validators';
|
import {AsyncValidatorFn, ValidatorFn} from '../validators';
|
||||||
|
|
||||||
|
|
||||||
export const controlNameBinding: any =
|
export const controlNameBinding: any =
|
||||||
|
@ -18,9 +18,9 @@ export const controlNameBinding: any =
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and binds a form control with a specified name to a DOM element.
|
* Syncs an existing form control with the specified name to a DOM element.
|
||||||
*
|
*
|
||||||
* This directive can only be used as a child of {@link NgForm} or {@link FormGroupDirective}.
|
* This directive can only be used as a child of {@link FormGroupDirective}.
|
||||||
|
|
||||||
* ### Example
|
* ### Example
|
||||||
*
|
*
|
|
@ -6,13 +6,13 @@ import {BaseException} from '../../../facade/exceptions';
|
||||||
import {isBlank} from '../../../facade/lang';
|
import {isBlank} from '../../../facade/lang';
|
||||||
import {FormControl, FormGroup} from '../../model';
|
import {FormControl, FormGroup} from '../../model';
|
||||||
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from '../../validators';
|
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS, Validators} from '../../validators';
|
||||||
|
|
||||||
import {ControlContainer} from '../control_container';
|
import {ControlContainer} from '../control_container';
|
||||||
import {Form} from '../form_interface';
|
import {Form} from '../form_interface';
|
||||||
import {NgControl} from '../ng_control';
|
import {NgControl} from '../ng_control';
|
||||||
import {NgControlGroup} from '../ng_control_group';
|
|
||||||
import {composeAsyncValidators, composeValidators, setUpControl, setUpFormGroup} from '../shared';
|
import {composeAsyncValidators, composeValidators, setUpControl, setUpFormGroup} from '../shared';
|
||||||
|
|
||||||
|
import {FormGroupName} from './form_group_name';
|
||||||
|
|
||||||
export const formDirectiveProvider: any =
|
export const formDirectiveProvider: any =
|
||||||
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
|
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
|
||||||
provide: ControlContainer,
|
provide: ControlContainer,
|
||||||
|
@ -148,15 +148,15 @@ export class FormGroupDirective extends ControlContainer implements Form,
|
||||||
|
|
||||||
removeControl(dir: NgControl): void { ListWrapper.remove(this.directives, dir); }
|
removeControl(dir: NgControl): void { ListWrapper.remove(this.directives, dir); }
|
||||||
|
|
||||||
addFormGroup(dir: NgControlGroup) {
|
addFormGroup(dir: FormGroupName) {
|
||||||
var ctrl: any = this.form.find(dir.path);
|
var ctrl: any = this.form.find(dir.path);
|
||||||
setUpFormGroup(ctrl, dir);
|
setUpFormGroup(ctrl, dir);
|
||||||
ctrl.updateValueAndValidity({emitEvent: false});
|
ctrl.updateValueAndValidity({emitEvent: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFormGroup(dir: NgControlGroup) {}
|
removeFormGroup(dir: FormGroupName) {}
|
||||||
|
|
||||||
getFormGroup(dir: NgControlGroup): FormGroup { return <FormGroup>this.form.find(dir.path); }
|
getFormGroup(dir: FormGroupName): FormGroup { return <FormGroup>this.form.find(dir.path); }
|
||||||
|
|
||||||
updateModel(dir: NgControl, value: any): void {
|
updateModel(dir: NgControl, value: any): void {
|
||||||
var ctrl = <FormControl>this.form.find(dir.path);
|
var ctrl = <FormControl>this.form.find(dir.path);
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
import {Directive, Host, Inject, Input, OnDestroy, OnInit, Optional, Self, SkipSelf, forwardRef} from '@angular/core';
|
||||||
|
import {NG_ASYNC_VALIDATORS, NG_VALIDATORS} from '../../validators';
|
||||||
|
import {AbstractFormGroupDirective} from '../abstract_form_group_directive';
|
||||||
|
import {ControlContainer} from '../control_container';
|
||||||
|
|
||||||
|
export const formGroupNameProvider: any =
|
||||||
|
/*@ts2dart_const*/ /* @ts2dart_Provider */ {
|
||||||
|
provide: ControlContainer,
|
||||||
|
useExisting: forwardRef(() => FormGroupName)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Syncs an existing form group 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 FormGroup Example</h2>
|
||||||
|
* <form [formGroup]="myForm">
|
||||||
|
* <div formGroupName="name">
|
||||||
|
* <h3>Enter your name:</h3>
|
||||||
|
* <p>First: <input formControlName="first"></p>
|
||||||
|
* <p>Middle: <input formControlName="middle"></p>
|
||||||
|
* <p>Last: <input formControlName="last"></p>
|
||||||
|
* </div>
|
||||||
|
* <h3>Name value:</h3>
|
||||||
|
* <pre>{{ nameGroup | json }}</pre>
|
||||||
|
* <p>Name is {{nameGroup?.valid ? "valid" : "invalid"}}</p>
|
||||||
|
* <h3>What's your favorite food?</h3>
|
||||||
|
* <p><input formControlName="food"></p>
|
||||||
|
* <h3>Form value</h3>
|
||||||
|
* <pre> {{ myForm | json }} </pre>
|
||||||
|
* </form>
|
||||||
|
* </div>
|
||||||
|
* `
|
||||||
|
* })
|
||||||
|
* export class App {
|
||||||
|
* nameGroup = new FormGroup({
|
||||||
|
* first: new FormControl('', Validators.required),
|
||||||
|
* middle: new FormControl(''),
|
||||||
|
* last: new FormControl('', Validators.required)
|
||||||
|
* });
|
||||||
|
*
|
||||||
|
* myForm = new FormGroup({
|
||||||
|
* name: this.nameGroup,
|
||||||
|
* food: new FormControl()
|
||||||
|
* });
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This example syncs the form group for the user's name. The value and validation state of
|
||||||
|
* this group can be accessed separately from the overall form.
|
||||||
|
*
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
@Directive({selector: '[formGroupName]', providers: [formGroupNameProvider]})
|
||||||
|
export class FormGroupName extends AbstractFormGroupDirective implements OnInit, OnDestroy {
|
||||||
|
@Input('formGroupName') name: string;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,12 +5,12 @@ import {FormControl, FormGroup} from '../model';
|
||||||
import {Validators} from '../validators';
|
import {Validators} from '../validators';
|
||||||
|
|
||||||
import {AbstractControlDirective} from './abstract_control_directive';
|
import {AbstractControlDirective} from './abstract_control_directive';
|
||||||
|
import {AbstractFormGroupDirective} from './abstract_form_group_directive';
|
||||||
import {CheckboxControlValueAccessor} from './checkbox_value_accessor';
|
import {CheckboxControlValueAccessor} from './checkbox_value_accessor';
|
||||||
import {ControlContainer} from './control_container';
|
import {ControlContainer} from './control_container';
|
||||||
import {ControlValueAccessor} from './control_value_accessor';
|
import {ControlValueAccessor} from './control_value_accessor';
|
||||||
import {DefaultValueAccessor} from './default_value_accessor';
|
import {DefaultValueAccessor} from './default_value_accessor';
|
||||||
import {NgControl} from './ng_control';
|
import {NgControl} from './ng_control';
|
||||||
import {NgControlGroup} from './ng_control_group';
|
|
||||||
import {normalizeAsyncValidator, normalizeValidator} from './normalize_validator';
|
import {normalizeAsyncValidator, normalizeValidator} from './normalize_validator';
|
||||||
import {NumberValueAccessor} from './number_value_accessor';
|
import {NumberValueAccessor} from './number_value_accessor';
|
||||||
import {RadioControlValueAccessor} from './radio_control_value_accessor';
|
import {RadioControlValueAccessor} from './radio_control_value_accessor';
|
||||||
|
@ -46,7 +46,7 @@ export function setUpControl(control: FormControl, dir: NgControl): void {
|
||||||
dir.valueAccessor.registerOnTouched(() => control.markAsTouched());
|
dir.valueAccessor.registerOnTouched(() => control.markAsTouched());
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setUpFormGroup(control: FormGroup, dir: NgControlGroup) {
|
export function setUpFormGroup(control: FormGroup, dir: AbstractFormGroupDirective) {
|
||||||
if (isBlank(control)) _throwError(dir, 'Cannot find control');
|
if (isBlank(control)) _throwError(dir, 'Cannot find control');
|
||||||
control.validator = Validators.compose([control.validator, dir.validator]);
|
control.validator = Validators.compose([control.validator, dir.validator]);
|
||||||
control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
|
control.asyncValidator = Validators.composeAsync([control.asyncValidator, dir.asyncValidator]);
|
||||||
|
|
|
@ -17,7 +17,7 @@ import * as modelModule from './model';
|
||||||
* template: `
|
* template: `
|
||||||
* <form [formGroup]="loginForm">
|
* <form [formGroup]="loginForm">
|
||||||
* <p>Login <input formControlName="login"></p>
|
* <p>Login <input formControlName="login"></p>
|
||||||
* <div ngControlGroup="passwordRetry">
|
* <div formGroupName="passwordRetry">
|
||||||
* <p>Password <input type="password" formControlName="password"></p>
|
* <p>Password <input type="password" formControlName="password"></p>
|
||||||
* <p>Confirm password <input type="password" formControlName="passwordConfirmation"></p>
|
* <p>Confirm password <input type="password" formControlName="passwordConfirmation"></p>
|
||||||
* </div>
|
* </div>
|
||||||
|
|
|
@ -4,8 +4,7 @@ import {fakeAsync, flushMicrotasks, Log, tick,} from '@angular/core/testing';
|
||||||
|
|
||||||
import {SpyNgControl, SpyValueAccessor} from '../spies';
|
import {SpyNgControl, SpyValueAccessor} from '../spies';
|
||||||
|
|
||||||
import {FormGroup, FormControl, FormControlName, NgControlGroup, FormGroupDirective, ControlValueAccessor, Validators, NgForm, NgModel, FormControlDirective, NgControl, DefaultValueAccessor, CheckboxControlValueAccessor, SelectControlValueAccessor, Validator} from '@angular/common/src/forms';
|
import {FormGroup, FormControl, FormControlName, FormGroupName, NgModelGroup, FormGroupDirective, ControlValueAccessor, Validators, NgForm, NgModel, FormControlDirective, NgControl, DefaultValueAccessor, CheckboxControlValueAccessor, SelectControlValueAccessor, Validator} from '@angular/common/src/forms';
|
||||||
|
|
||||||
|
|
||||||
import {selectValueAccessor, composeValidators} from '@angular/common/src/forms/directives/shared';
|
import {selectValueAccessor, composeValidators} from '@angular/common/src/forms/directives/shared';
|
||||||
import {TimerWrapper} from '../../src/facade/async';
|
import {TimerWrapper} from '../../src/facade/async';
|
||||||
|
@ -195,7 +194,7 @@ export function main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
it('should set up validator', fakeAsync(() => {
|
it('should set up validator', fakeAsync(() => {
|
||||||
var group = new NgControlGroup(
|
var group = new FormGroupName(
|
||||||
form, [matchingPasswordsValidator], [asyncValidator('expected')]);
|
form, [matchingPasswordsValidator], [asyncValidator('expected')]);
|
||||||
group.name = 'passwords';
|
group.name = 'passwords';
|
||||||
form.addFormGroup(group);
|
form.addFormGroup(group);
|
||||||
|
@ -271,7 +270,7 @@ export function main() {
|
||||||
form = new NgForm([], []);
|
form = new NgForm([], []);
|
||||||
formModel = form.form;
|
formModel = form.form;
|
||||||
|
|
||||||
personControlGroupDir = new NgControlGroup(form, [], []);
|
personControlGroupDir = new NgModelGroup(form, [], []);
|
||||||
personControlGroupDir.name = 'person';
|
personControlGroupDir.name = 'person';
|
||||||
|
|
||||||
loginControlDir = new FormControlName(personControlGroupDir, null, null, [defaultAccessor]);
|
loginControlDir = new FormControlName(personControlGroupDir, null, null, [defaultAccessor]);
|
||||||
|
@ -338,7 +337,7 @@ export function main() {
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('NgControlGroup', () => {
|
describe('FormGroupName', () => {
|
||||||
var formModel: any /** TODO #9100 */;
|
var formModel: any /** TODO #9100 */;
|
||||||
var controlGroupDir: any /** TODO #9100 */;
|
var controlGroupDir: any /** TODO #9100 */;
|
||||||
|
|
||||||
|
@ -347,7 +346,7 @@ export function main() {
|
||||||
|
|
||||||
var parent = new FormGroupDirective([], []);
|
var parent = new FormGroupDirective([], []);
|
||||||
parent.form = new FormGroup({'group': formModel});
|
parent.form = new FormGroup({'group': formModel});
|
||||||
controlGroupDir = new NgControlGroup(parent, [], []);
|
controlGroupDir = new FormGroupName(parent, [], []);
|
||||||
controlGroupDir.name = 'group';
|
controlGroupDir.name = 'group';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -991,7 +991,7 @@ export function main() {
|
||||||
new FormGroup({'nested': new FormGroup({'login': new FormControl('value')})});
|
new FormGroup({'nested': new FormGroup({'login': new FormControl('value')})});
|
||||||
|
|
||||||
const t = `<div [formGroup]="form">
|
const t = `<div [formGroup]="form">
|
||||||
<div ngControlGroup="nested">
|
<div formGroupName="nested">
|
||||||
<input type="text" formControlName="login">
|
<input type="text" formControlName="login">
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
@ -1014,7 +1014,7 @@ export function main() {
|
||||||
new FormGroup({'nested': new FormGroup({'login': new FormControl('value')})});
|
new FormGroup({'nested': new FormGroup({'login': new FormControl('value')})});
|
||||||
|
|
||||||
const t = `<div [formGroup]="form">
|
const t = `<div [formGroup]="form">
|
||||||
<div ngControlGroup="nested">
|
<div formGroupName="nested">
|
||||||
<input type="text" formControlName="login">
|
<input type="text" formControlName="login">
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
@ -1083,8 +1083,8 @@ export function main() {
|
||||||
it('should add new controls and control groups',
|
it('should add new controls and control groups',
|
||||||
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
const t = `<form>
|
const t = `<form>
|
||||||
<div ngControlGroup="user">
|
<div ngModelGroup="user">
|
||||||
<input type="text" formControlName="login">
|
<input type="text" name="login" ngModel>
|
||||||
</div>
|
</div>
|
||||||
</form>`;
|
</form>`;
|
||||||
|
|
||||||
|
@ -1137,7 +1137,7 @@ export function main() {
|
||||||
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
const t = `<form>
|
const t = `<form>
|
||||||
<div *ngIf="name == 'show'">
|
<div *ngIf="name == 'show'">
|
||||||
<input type="text" formControlName="login">
|
<input type="text" name="login" ngModel>
|
||||||
</div>
|
</div>
|
||||||
</form>`;
|
</form>`;
|
||||||
|
|
||||||
|
@ -1161,7 +1161,7 @@ export function main() {
|
||||||
it('should remove control groups',
|
it('should remove control groups',
|
||||||
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
fakeAsync(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
|
||||||
const t = `<form>
|
const t = `<form>
|
||||||
<div *ngIf="name=='show'" ngControlGroup="user">
|
<div *ngIf="name=='show'" ngModelGroup="user">
|
||||||
<input type="text" name="login" ngModel>
|
<input type="text" name="login" ngModel>
|
||||||
</div>
|
</div>
|
||||||
</form>`;
|
</form>`;
|
||||||
|
@ -1492,7 +1492,7 @@ export function main() {
|
||||||
// {{x.valid}} used to crash because valid() tried to read a property
|
// {{x.valid}} used to crash because valid() tried to read a property
|
||||||
// from form.control before it was set. This test verifies this bug is
|
// from form.control before it was set. This test verifies this bug is
|
||||||
// fixed.
|
// fixed.
|
||||||
const t = `<form><div ngControlGroup="x" #x="ngForm">
|
const t = `<form><div ngModelGroup="x" #x="ngModelGroup">
|
||||||
<input type="text" name="test" ngModel></div>{{x.valid}}</form>`;
|
<input type="text" name="test" ngModel></div>{{x.valid}}</form>`;
|
||||||
let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8);
|
let fixture = tcb.overrideTemplate(MyComp8, t).createFakeAsync(MyComp8);
|
||||||
tick();
|
tick();
|
||||||
|
|
Loading…
Reference in New Issue