diff --git a/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.css b/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.css
index 08fa67536b1f..951aee759961 100644
--- a/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.css
+++ b/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.css
@@ -2,6 +2,7 @@
min-width: 150px;
max-width: 500px;
width: 100%;
+ margin-top: 16px;
}
.example-full-width {
diff --git a/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.html b/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.html
index 6b428b0b45c9..e5c96b37e9d3 100644
--- a/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.html
+++ b/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.html
@@ -1,18 +1,20 @@
+Control value: {{myControl.value || 'empty'}}
+
-
-Control value: {{myControl.value}}
diff --git a/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.ts b/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.ts
index a93619ae3748..5da4fc881088 100644
--- a/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.ts
+++ b/src/components-examples/material/autocomplete/autocomplete-require-selection/autocomplete-require-selection-example.ts
@@ -1,14 +1,12 @@
-import {Component, OnInit} from '@angular/core';
+import {Component, ElementRef, ViewChild} from '@angular/core';
import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms';
-import {Observable} from 'rxjs';
-import {map, startWith} from 'rxjs/operators';
import {NgFor, AsyncPipe} from '@angular/common';
import {MatAutocompleteModule} from '@angular/material/autocomplete';
import {MatInputModule} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
/**
- * @title Require an autocomplete option to be selected.
+ * @title Require an autocomplete option to be selected
*/
@Component({
selector: 'autocomplete-require-selection-example',
@@ -25,21 +23,18 @@ import {MatFormFieldModule} from '@angular/material/form-field';
AsyncPipe,
],
})
-export class AutocompleteRequireSelectionExample implements OnInit {
+export class AutocompleteRequireSelectionExample {
+ @ViewChild('input') input: ElementRef;
myControl = new FormControl('');
- options: string[] = ['One', 'Two', 'Three', 'Three', 'Four'];
- filteredOptions: Observable;
+ options: string[] = ['One', 'Two', 'Three', 'Four', 'Five'];
+ filteredOptions: string[];
- ngOnInit() {
- this.filteredOptions = this.myControl.valueChanges.pipe(
- startWith(''),
- map(value => this._filter(value || '')),
- );
+ constructor() {
+ this.filteredOptions = this.options.slice();
}
- private _filter(value: string): string[] {
- const filterValue = value.toLowerCase();
-
- return this.options.filter(option => option.toLowerCase().includes(filterValue));
+ filter(): void {
+ const filterValue = this.input.nativeElement.value.toLowerCase();
+ this.filteredOptions = this.options.filter(o => o.toLowerCase().includes(filterValue));
}
}
diff --git a/src/dev-app/autocomplete/autocomplete-demo.html b/src/dev-app/autocomplete/autocomplete-demo.html
index e2d04e637bd8..27960dc3fce6 100644
--- a/src/dev-app/autocomplete/autocomplete-demo.html
+++ b/src/dev-app/autocomplete/autocomplete-demo.html
@@ -1,21 +1,27 @@
Space above cards:
-
- Reactive length: {{ tempStates?.length }}
+
+ Reactive length: {{ reactiveStates.length }}
Reactive value: {{ stateCtrl.value | json }}
Reactive dirty: {{ stateCtrl.dirty }}
State
-
+
-
{{ state.name }}
({{ state.code }})
diff --git a/src/dev-app/autocomplete/autocomplete-demo.ts b/src/dev-app/autocomplete/autocomplete-demo.ts
index d43a358ad72d..8c87e89ae06c 100644
--- a/src/dev-app/autocomplete/autocomplete-demo.ts
+++ b/src/dev-app/autocomplete/autocomplete-demo.ts
@@ -14,8 +14,6 @@ import {MatButtonModule} from '@angular/material/button';
import {MatCardModule} from '@angular/material/card';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatInputModule} from '@angular/material/input';
-import {Observable} from 'rxjs';
-import {map, startWith} from 'rxjs/operators';
import {ThemePalette} from '@angular/material/core';
import {MatDialog, MatDialogModule, MatDialogRef} from '@angular/material/dialog';
@@ -50,12 +48,12 @@ type DisableStateOption = 'none' | 'first-middle-last' | 'all';
],
})
export class AutocompleteDemo {
- stateCtrl = new FormControl({code: 'CA', name: 'California'});
+ stateCtrl = new FormControl();
currentState = '';
currentGroupedState = '';
topHeightCtrl = new FormControl(0);
- reactiveStates: Observable;
+ reactiveStates: State[];
tdStates: State[];
tdDisabled = false;
@@ -138,12 +136,8 @@ export class AutocompleteDemo {
].map((state, index) => ({...state, index}));
constructor() {
- this.tdStates = this.states;
- this.reactiveStates = this.stateCtrl.valueChanges.pipe(
- startWith(this.stateCtrl.value),
- map(val => this.displayFn(val)),
- map(name => this.filterStates(name)),
- );
+ this.tdStates = this.states.slice();
+ this.reactiveStates = this.states.slice();
this.filteredGroupedStates = this.groupedStates = this.states.reduce(
(groups, state) => {
diff --git a/src/material/autocomplete/autocomplete-trigger.ts b/src/material/autocomplete/autocomplete-trigger.ts
index 9a2460b75c39..b2cd6c5612e4 100644
--- a/src/material/autocomplete/autocomplete-trigger.ts
+++ b/src/material/autocomplete/autocomplete-trigger.ts
@@ -470,7 +470,13 @@ export abstract class _MatAutocompleteTriggerBase
if (this._previousValue !== value) {
this._previousValue = value;
this._pendingAutoselectedOption = null;
- this._onChange(value);
+
+ // If selection is required we don't write to the CVA while the user is typing.
+ // At the end of the selection either the user will have picked something
+ // or we'll reset the value back to null.
+ if (!this.autocomplete || !this.autocomplete.requireSelection) {
+ this._onChange(value);
+ }
if (!value) {
this._clearPreviousSelectedOption(null, false);
diff --git a/src/material/autocomplete/autocomplete.spec.ts b/src/material/autocomplete/autocomplete.spec.ts
index ca4dd3f62773..27365fa5b76f 100644
--- a/src/material/autocomplete/autocomplete.spec.ts
+++ b/src/material/autocomplete/autocomplete.spec.ts
@@ -2622,7 +2622,7 @@ describe('MDC-based MatAutocomplete', () => {
tick();
expect(input.value).toBe('Cali');
- expect(stateCtrl.value).toBe('Cali');
+ expect(stateCtrl.value).toEqual({code: 'CA', name: 'California'});
expect(spy).not.toHaveBeenCalled();
dispatchFakeEvent(document, 'click');