docs(forms): add select control examples (#11728)
This commit is contained in:
parent
0621f07a2c
commit
bf81b06a28
|
@ -0,0 +1,36 @@
|
||||||
|
/**
|
||||||
|
* @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('reactiveSelectControl example', () => {
|
||||||
|
afterEach(verifyNoBrowserErrors);
|
||||||
|
let select: protractor.ElementFinder;
|
||||||
|
let options: protractor.ElementArrayFinder;
|
||||||
|
let p: protractor.ElementFinder;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
browser.get('/forms/ts/reactiveSelectControl/index.html');
|
||||||
|
select = element(by.css('select'));
|
||||||
|
options = element.all(by.css('option'));
|
||||||
|
p = element(by.css('p'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should populate the initial selection', () => {
|
||||||
|
expect(select.getAttribute('value')).toEqual('3: Object');
|
||||||
|
expect(options.get(3).getAttribute('selected')).toBe('true');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should update the model when the value changes in the UI', () => {
|
||||||
|
select.click();
|
||||||
|
options.get(0).click();
|
||||||
|
|
||||||
|
expect(p.getText()).toEqual('Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -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 {ReactiveSelectComp} from './reactive_select_control_example';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [BrowserModule, ReactiveFormsModule],
|
||||||
|
declarations: [ReactiveSelectComp],
|
||||||
|
bootstrap: [ReactiveSelectComp]
|
||||||
|
})
|
||||||
|
export class AppModule {
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* @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 {FormControl, FormGroup} from '@angular/forms';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'example-app',
|
||||||
|
template: `
|
||||||
|
<form [formGroup]="form">
|
||||||
|
<select formControlName="state">
|
||||||
|
<option *ngFor="let state of states" [ngValue]="state">
|
||||||
|
{{ state.abbrev }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p>Form value: {{ form.value | json }}</p>
|
||||||
|
<!-- {state: {name: 'New York', abbrev: 'NY'} } -->
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class ReactiveSelectComp {
|
||||||
|
states = [
|
||||||
|
{name: 'Arizona', abbrev: 'AZ'},
|
||||||
|
{name: 'California', abbrev: 'CA'},
|
||||||
|
{name: 'Colorado', abbrev: 'CO'},
|
||||||
|
{name: 'New York', abbrev: 'NY'},
|
||||||
|
{name: 'Pennsylvania', abbrev: 'PA'},
|
||||||
|
];
|
||||||
|
|
||||||
|
form = new FormGroup({
|
||||||
|
state: new FormControl(this.states[3]),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// #enddocregion
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* @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('selectControl example', () => {
|
||||||
|
afterEach(verifyNoBrowserErrors);
|
||||||
|
let select: protractor.ElementFinder;
|
||||||
|
let options: protractor.ElementArrayFinder;
|
||||||
|
let p: protractor.ElementFinder;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
browser.get('/forms/ts/selectControl/index.html');
|
||||||
|
select = element(by.css('select'));
|
||||||
|
options = element.all(by.css('option'));
|
||||||
|
p = element(by.css('p'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should initially select the placeholder option',
|
||||||
|
() => { expect(options.get(0).getAttribute('selected')).toBe('true'); });
|
||||||
|
|
||||||
|
it('should update the model when the value changes in the UI', () => {
|
||||||
|
select.click();
|
||||||
|
options.get(1).click();
|
||||||
|
|
||||||
|
expect(p.getText()).toEqual('Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -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 {FormsModule} from '@angular/forms';
|
||||||
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
|
import {SelectControlComp} from './select_control_example';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
imports: [BrowserModule, FormsModule],
|
||||||
|
declarations: [SelectControlComp],
|
||||||
|
bootstrap: [SelectControlComp]
|
||||||
|
})
|
||||||
|
export class AppModule {
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
* @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';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'example-app',
|
||||||
|
template: `
|
||||||
|
<form #f="ngForm">
|
||||||
|
<select name="state" ngModel>
|
||||||
|
<option value="" disabled>Choose a state</option>
|
||||||
|
<option *ngFor="let state of states" [ngValue]="state">
|
||||||
|
{{ state.abbrev }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p>Form value: {{ f.value | json }}</p>
|
||||||
|
<!-- example value: {state: {name: 'New York', abbrev: 'NY'} } -->
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
export class SelectControlComp {
|
||||||
|
states = [
|
||||||
|
{name: 'Arizona', abbrev: 'AZ'},
|
||||||
|
{name: 'California', abbrev: 'CA'},
|
||||||
|
{name: 'Colorado', abbrev: 'CO'},
|
||||||
|
{name: 'New York', abbrev: 'NY'},
|
||||||
|
{name: 'Pennsylvania', abbrev: 'PA'},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
// #enddocregion
|
|
@ -76,6 +76,11 @@ const resolvedPromise = Promise.resolve(null);
|
||||||
*
|
*
|
||||||
* {@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
|
* {@example forms/ts/simpleForm/simple_form_example.ts region='Component'}
|
||||||
*
|
*
|
||||||
|
* To see `ngModel` examples with different form control types, see:
|
||||||
|
*
|
||||||
|
* * Radio buttons: {@link RadioControlValueAccessor}
|
||||||
|
* * Selects: {@link SelectControlValueAccessor}
|
||||||
|
*
|
||||||
* **npm package**: `@angular/forms`
|
* **npm package**: `@angular/forms`
|
||||||
*
|
*
|
||||||
* **NgModule**: `FormsModule`
|
* **NgModule**: `FormsModule`
|
||||||
|
|
|
@ -67,9 +67,14 @@ export const controlNameBinding: any = {
|
||||||
*
|
*
|
||||||
* {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
|
* {@example forms/ts/simpleFormGroup/simple_form_group_example.ts region='Component'}
|
||||||
*
|
*
|
||||||
* * **npm package**: `@angular/forms`
|
* To see `formControlName` examples with different form control types, see:
|
||||||
*
|
*
|
||||||
* * **NgModule**: {@link ReactiveFormsModule}
|
* * Radio buttons: {@link RadioControlValueAccessor}
|
||||||
|
* * Selects: {@link SelectControlValueAccessor}
|
||||||
|
*
|
||||||
|
* **npm package**: `@angular/forms`
|
||||||
|
*
|
||||||
|
* **NgModule**: {@link ReactiveFormsModule}
|
||||||
*
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -30,13 +30,41 @@ function _extractId(valueString: string): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The accessor for writing a value and listening to changes on a select element.
|
* @whatItDoes Writes values and listens to changes on a select element.
|
||||||
*
|
*
|
||||||
* Note: We have to listen to the 'change' event because 'input' events aren't fired
|
* Used by {@link NgModel}, {@link FormControlDirective}, and {@link FormControlName}
|
||||||
|
* to keep the view synced with the {@link FormControl} model.
|
||||||
|
*
|
||||||
|
* @howToUse
|
||||||
|
*
|
||||||
|
* If you have imported the {@link FormsModule} or the {@link ReactiveFormsModule}, this
|
||||||
|
* value accessor will be active on any select control that has a form directive. You do
|
||||||
|
* **not** need to add a special selector to activate it.
|
||||||
|
*
|
||||||
|
* ### How to use select controls with form directives
|
||||||
|
*
|
||||||
|
* To use a select in a template-driven form, simply add an `ngModel` and a `name`
|
||||||
|
* attribute to the main `<select>` tag.
|
||||||
|
*
|
||||||
|
* If your option values are simple strings, you can bind to the normal `value` property
|
||||||
|
* on the option. If your option values happen to be objects (and you'd like to save the
|
||||||
|
* selection in your form as an object), use `ngValue` instead:
|
||||||
|
*
|
||||||
|
* {@example forms/ts/selectControl/select_control_example.ts region='Component'}
|
||||||
|
*
|
||||||
|
* In reactive forms, you'll also want to add your form directive (`formControlName` or
|
||||||
|
* `formControl`) on the main `<select>` tag. Like in the former example, you have the
|
||||||
|
* choice of binding to the `value` or `ngValue` property on the select's options.
|
||||||
|
*
|
||||||
|
* {@example forms/ts/reactiveSelectControl/reactive_select_control_example.ts region='Component'}
|
||||||
|
*
|
||||||
|
* Note: We listen to the 'change' event because 'input' events aren't fired
|
||||||
* for selects in Firefox and IE:
|
* for selects in Firefox and IE:
|
||||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1024350
|
* https://bugzilla.mozilla.org/show_bug.cgi?id=1024350
|
||||||
* https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4660045/
|
* https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/4660045/
|
||||||
*
|
*
|
||||||
|
* * **npm package**: `@angular/forms`
|
||||||
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
@Directive({
|
@Directive({
|
||||||
|
@ -94,15 +122,11 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Marks `<option>` as dynamic, so Angular can be notified when options change.
|
* @whatItDoes Marks `<option>` as dynamic, so Angular can be notified when options change.
|
||||||
*
|
*
|
||||||
* ### Example
|
* @howToUse
|
||||||
*
|
*
|
||||||
* ```
|
* See docs for {@link SelectControlValueAccessor} for usage examples.
|
||||||
* <select name="city" ngModel>
|
|
||||||
* <option *ngFor="let c of cities" [value]="c"></option>
|
|
||||||
* </select>
|
|
||||||
* ```
|
|
||||||
*
|
*
|
||||||
* @stable
|
* @stable
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue