@@ -29,7 +29,7 @@ import {
29
29
ErrorStateMatcher ,
30
30
mixinErrorState ,
31
31
} from '@angular/material/core' ;
32
- import { MatFormFieldControl } from '@angular/material/form-field' ;
32
+ import { MatFormFieldControl , MatFormField } from '@angular/material/form-field' ;
33
33
import { Subject } from 'rxjs' ;
34
34
import { getMatInputUnsupportedTypeError } from './input-errors' ;
35
35
import { MAT_INPUT_VALUE_ACCESSOR } from './input-value-accessor' ;
@@ -76,7 +76,7 @@ const _MatInputMixinBase: CanUpdateErrorStateCtor & typeof MatInputBase =
76
76
// Native input properties that are overwritten by Angular inputs need to be synced with
77
77
// the native input element. Otherwise property bindings for those don't work.
78
78
'[attr.id]' : 'id' ,
79
- '[attr.placeholder]' : 'placeholder ' ,
79
+ '[attr.placeholder]' : '_getNativePlaceholderValue() ' ,
80
80
'[disabled]' : 'disabled' ,
81
81
'[required]' : 'required' ,
82
82
'[attr.readonly]' : 'readonly && !_isNativeSelect || null' ,
@@ -231,8 +231,9 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
231
231
_defaultErrorStateMatcher : ErrorStateMatcher ,
232
232
@Optional ( ) @Self ( ) @Inject ( MAT_INPUT_VALUE_ACCESSOR ) inputValueAccessor : any ,
233
233
private _autofillMonitor : AutofillMonitor ,
234
- ngZone : NgZone ) {
235
-
234
+ ngZone : NgZone ,
235
+ // @breaking -change 8.0.0 `_formField` parameter to be made required.
236
+ @Optional ( ) private _formField ?: MatFormField ) {
236
237
super ( _defaultErrorStateMatcher , _parentForm , _parentFormGroup , ngControl ) ;
237
238
238
239
const element = this . _elementRef . nativeElement ;
@@ -332,6 +333,16 @@ export class MatInput extends _MatInputMixinBase implements MatFormFieldControl<
332
333
// FormsModule or ReactiveFormsModule, because Angular forms also listens to input events.
333
334
}
334
335
336
+ /** Determines the value of the native `placeholder` attribute that should be used in the DOM. */
337
+ _getNativePlaceholderValue ( ) {
338
+ // If we're hiding the native placeholder, it should also be cleared from the DOM, otherwise
339
+ // screen readers will read it out twice: once from the label and once from the attribute.
340
+ // TODO: can be removed once we get rid of the `legacy` style for the form field, because it's
341
+ // the only one that supports promoting the placeholder to a label.
342
+ const formField = this . _formField ;
343
+ return ( ! formField || ! formField . _hideControlPlaceholder ( ) ) ? this . placeholder : null ;
344
+ }
345
+
335
346
/** Does some manual dirty checking on the native input `value` property. */
336
347
protected _dirtyCheckNativeValue ( ) {
337
348
const newValue = this . _elementRef . nativeElement . value ;
0 commit comments