diff --git a/src/material-experimental/mdc-input/input.spec.ts b/src/material-experimental/mdc-input/input.spec.ts
index b971b87f59cd..aeb294f15cb6 100644
--- a/src/material-experimental/mdc-input/input.spec.ts
+++ b/src/material-experimental/mdc-input/input.spec.ts
@@ -327,6 +327,16 @@ describe('MatMdcInput without forms', () => {
expect(label.nativeElement.classList).toContain('mdc-floating-label--required');
}));
+ it('should show the required star when using a FormControl', fakeAsync(() => {
+ const fixture = createComponent(MatInputWithRequiredFormControl);
+ fixture.detectChanges();
+
+ const label = fixture.debugElement.query(By.css('label'))!;
+ expect(label).not.toBeNull();
+ expect(label.nativeElement.textContent).toBe('Hello');
+ expect(label.nativeElement.classList).toContain('mdc-floating-label--required');
+ }));
+
it('should not hide the required star if input is disabled', () => {
const fixture = createComponent(MatInputLabelRequiredTestComponent);
@@ -1058,7 +1068,7 @@ describe('MatMdcInput with forms', () => {
expect(testComponent.formControl.invalid)
.withContext('Expected form control to be invalid').toBe(true);
- expect(inputEl.value).toBeFalsy();
+ expect(inputEl.value).toBe('incorrect');
expect(inputEl.getAttribute('aria-invalid'))
.withContext('Expected aria-invalid to be set to "true"').toBe('true');
@@ -1548,7 +1558,10 @@ class MatInputMissingMatInputTestController {}
})
class MatInputWithFormErrorMessages {
@ViewChild('form') form: NgForm;
- formControl = new FormControl('', [Validators.required, Validators.pattern(/valid value/)]);
+ formControl = new FormControl('incorrect', [
+ Validators.required,
+ Validators.pattern(/valid value/)
+ ]);
renderError = true;
}
@@ -1591,7 +1604,7 @@ class MatInputWithCustomErrorStateMatcher {
class MatInputWithFormGroupErrorMessages {
@ViewChild(FormGroupDirective) formGroupDirective: FormGroupDirective;
formGroup = new FormGroup({
- name: new FormControl('', [Validators.required, Validators.pattern(/valid value/)])
+ name: new FormControl('incorrect', [Validators.required, Validators.pattern(/valid value/)])
});
}
@@ -1790,3 +1803,15 @@ class MatInputWithColor {
`
})
class MatInputInsideOutsideFormField {}
+
+
+@Component({
+ template: `
+
+ Hello
+
+ `
+})
+class MatInputWithRequiredFormControl {
+ formControl = new FormControl('', [Validators.required]);
+}
diff --git a/src/material/input/input.spec.ts b/src/material/input/input.spec.ts
index 4532c2fecdf2..5167ffe80445 100644
--- a/src/material/input/input.spec.ts
+++ b/src/material/input/input.spec.ts
@@ -410,6 +410,15 @@ describe('MatInput without forms', () => {
expect(labelEl.nativeElement.textContent).toBe('hello *');
}));
+ it('should show the required star when using a FormControl', fakeAsync(() => {
+ const fixture = createComponent(MatInputWithRequiredFormControl);
+ fixture.detectChanges();
+
+ const labelEl = fixture.debugElement.query(By.css('label'))!;
+ expect(labelEl).not.toBeNull();
+ expect(labelEl.nativeElement.textContent).toBe('Hello *');
+ }));
+
it('should hide the required star if input is disabled', () => {
const fixture = createComponent(MatInputPlaceholderRequiredTestComponent);
@@ -1203,7 +1212,7 @@ describe('MatInput with forms', () => {
expect(testComponent.formControl.invalid)
.withContext('Expected form control to be invalid').toBe(true);
- expect(inputEl.value).toBeFalsy();
+ expect(inputEl.value).toBe('incorrect');
expect(inputEl.getAttribute('aria-invalid'))
.withContext('Expected aria-invalid to be set to "true".').toBe('true');
@@ -2018,7 +2027,10 @@ class MatInputMissingMatInputTestController {}
})
class MatInputWithFormErrorMessages {
@ViewChild('form') form: NgForm;
- formControl = new FormControl('', [Validators.required, Validators.pattern(/valid value/)]);
+ formControl = new FormControl('incorrect', [
+ Validators.required,
+ Validators.pattern(/valid value/)
+ ]);
renderError = true;
}
@@ -2061,7 +2073,7 @@ class MatInputWithCustomErrorStateMatcher {
class MatInputWithFormGroupErrorMessages {
@ViewChild(FormGroupDirective) formGroupDirective: FormGroupDirective;
formGroup = new FormGroup({
- name: new FormControl('', [Validators.required, Validators.pattern(/valid value/)])
+ name: new FormControl('incorrect', [Validators.required, Validators.pattern(/valid value/)])
});
}
@@ -2360,3 +2372,14 @@ class MatInputWithAnotherNgIf {
class MatInputWithColor {
color: ThemePalette;
}
+
+
+@Component({
+ template: `
+
+
+ `
+})
+class MatInputWithRequiredFormControl {
+ formControl = new FormControl('', [Validators.required]);
+}
diff --git a/src/material/input/input.ts b/src/material/input/input.ts
index 527fa03d3902..0391ad8dec1d 100644
--- a/src/material/input/input.ts
+++ b/src/material/input/input.ts
@@ -23,7 +23,7 @@ import {
Optional,
Self,
} from '@angular/core';
-import {FormGroupDirective, NgControl, NgForm} from '@angular/forms';
+import {FormGroupDirective, NgControl, NgForm, Validators} from '@angular/forms';
import {
CanUpdateErrorState,
ErrorStateMatcher,
@@ -174,9 +174,11 @@ export class MatInput extends _MatInputBase implements MatFormFieldControl,
* @docs-private
*/
@Input()
- get required(): boolean { return this._required; }
+ get required(): boolean {
+ return this._required ?? this.ngControl?.control?.hasValidator(Validators.required) ?? false;
+ }
set required(value: boolean) { this._required = coerceBooleanProperty(value); }
- protected _required = false;
+ protected _required: boolean | undefined;
/** Input type of the element. */
@Input()
diff --git a/tools/public_api_guard/material/input.md b/tools/public_api_guard/material/input.md
index 5f9e485d2be7..32f3ebc27335 100644
--- a/tools/public_api_guard/material/input.md
+++ b/tools/public_api_guard/material/input.md
@@ -96,7 +96,7 @@ export class MatInput extends _MatInputBase implements MatFormFieldControl,
get required(): boolean;
set required(value: boolean);
// (undocumented)
- protected _required: boolean;
+ protected _required: boolean | undefined;
setDescribedByIds(ids: string[]): void;
get shouldLabelFloat(): boolean;
readonly stateChanges: Subject;