Skip to content

Commit

Permalink
fix(input): continue checking for input child after initialization (#…
Browse files Browse the repository at this point in the history
…4569)

Currently we only check if an `md-input-container` has a child upon initialization, however the child might be removed via `ngIf` at a later point. If that happens, we eventually run into some check that assumed that we have an input child, however it would be better if we threw the appropriate error. These changes add extra validation that ensure that the input continues to be in place after init.

Fixes #4551.
  • Loading branch information
crisbeto authored and jelbourn committed May 17, 2017
1 parent 43e207c commit 73d6814
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 19 deletions.
24 changes: 24 additions & 0 deletions src/lib/input/input-container.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ describe('MdInputContainer', function () {
MdInputContainerWithValueBinding,
MdInputContainerZeroTestController,
MdTextareaWithBindings,
MdInputContainerWithNgIf,
],
});

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -997,3 +1010,14 @@ class MdInputContainerWithFormGroupErrorMessages {
`
})
class MdInputContainerWithPrefixAndSuffix {}

@Component({
template: `
<md-input-container>
<input mdInput *ngIf="renderInput">
</md-input-container>
`
})
class MdInputContainerWithNgIf {
renderInput = true;
}
51 changes: 32 additions & 19 deletions src/lib/input/input-container.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
AfterContentInit,
AfterContentChecked,
AfterViewInit,
ChangeDetectorRef,
Component,
Expand Down Expand Up @@ -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';

Expand Down Expand Up @@ -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();

Expand All @@ -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';
Expand Down Expand Up @@ -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(' ');
}
}

0 comments on commit 73d6814

Please sign in to comment.