diff --git a/src/lib/input/input-container.spec.ts b/src/lib/input/input-container.spec.ts index 7ce05fc5bc7c..584ea076fb65 100644 --- a/src/lib/input/input-container.spec.ts +++ b/src/lib/input/input-container.spec.ts @@ -65,6 +65,7 @@ describe('MdInputContainer', function () { MdInputContainerWithValueBinding, MdInputContainerZeroTestController, MdTextareaWithBindings, + MdInputContainerWithNgIf, ], }); @@ -266,6 +267,18 @@ describe('MdInputContainer', function () { wrappedErrorMessage(getMdInputContainerMissingMdInputError())); }); + it('validates that mdInput child is present after initialization', async(() => { + let fixture = TestBed.createComponent(MdInputContainerWithNgIf); + + expect(() => fixture.detectChanges()).not.toThrowError( + wrappedErrorMessage(getMdInputContainerMissingMdInputError())); + + fixture.componentInstance.renderInput = false; + + expect(() => fixture.detectChanges()).toThrowError( + wrappedErrorMessage(getMdInputContainerMissingMdInputError())); + })); + it('validates the type', () => { let fixture = TestBed.createComponent(MdInputContainerInvalidTypeTestController); @@ -997,3 +1010,14 @@ class MdInputContainerWithFormGroupErrorMessages { ` }) class MdInputContainerWithPrefixAndSuffix {} + +@Component({ + template: ` + + + + ` +}) +class MdInputContainerWithNgIf { + renderInput = true; +} diff --git a/src/lib/input/input-container.ts b/src/lib/input/input-container.ts index 964b203cf4d9..c7ffb4d47f5d 100644 --- a/src/lib/input/input-container.ts +++ b/src/lib/input/input-container.ts @@ -1,5 +1,6 @@ import { AfterContentInit, + AfterContentChecked, AfterViewInit, ChangeDetectorRef, Component, @@ -286,7 +287,7 @@ export class MdInputDirective { }, encapsulation: ViewEncapsulation.None, }) -export class MdInputContainer implements AfterViewInit, AfterContentInit { +export class MdInputContainer implements AfterViewInit, AfterContentInit, AfterContentChecked { /** Alignment of the input container's content. */ @Input() align: 'start' | 'end' = 'start'; @@ -356,10 +357,7 @@ export class MdInputContainer implements AfterViewInit, AfterContentInit { @Optional() private _parentFormGroup: FormGroupDirective) { } ngAfterContentInit() { - if (!this._mdInputChild) { - throw getMdInputContainerMissingMdInputError(); - } - + this._validateInputChild(); this._processHints(); this._validatePlaceholders(); @@ -368,6 +366,10 @@ export class MdInputContainer implements AfterViewInit, AfterContentInit { this._mdInputChild._placeholderChange.subscribe(() => this._validatePlaceholders()); } + ngAfterContentChecked() { + this._validateInputChild(); + } + ngAfterViewInit() { // Avoid animations on load. this._subscriptAnimationState = 'enter'; @@ -449,22 +451,33 @@ export class MdInputContainer implements AfterViewInit, AfterContentInit { * of the currently-specified hints, as well as a generated id for the hint label. */ private _syncAriaDescribedby() { - let ids: string[] = []; - let startHint = this._hintChildren ? - this._hintChildren.find(hint => hint.align === 'start') : null; - let endHint = this._hintChildren ? - this._hintChildren.find(hint => hint.align === 'end') : null; - - if (startHint) { - ids.push(startHint.id); - } else if (this._hintLabel) { - ids.push(this._hintLabelId); + if (this._mdInputChild) { + let ids: string[] = []; + let startHint = this._hintChildren ? + this._hintChildren.find(hint => hint.align === 'start') : null; + let endHint = this._hintChildren ? + this._hintChildren.find(hint => hint.align === 'end') : null; + + if (startHint) { + ids.push(startHint.id); + } else if (this._hintLabel) { + ids.push(this._hintLabelId); + } + + if (endHint) { + ids.push(endHint.id); + } + + this._mdInputChild.ariaDescribedby = ids.join(' '); } + } - if (endHint) { - ids.push(endHint.id); + /** + * Throws an error if the container's input child was removed. + */ + private _validateInputChild() { + if (!this._mdInputChild) { + throw getMdInputContainerMissingMdInputError(); } - - this._mdInputChild.ariaDescribedby = ids.join(' '); } }