Skip to content

Commit b2df2a2

Browse files
mmalerbajelbourn
authored andcommitted
chore(input): improve error when md-input-container has no md-input (#2253)
* fix cryptic error when md-input-container has no md-input * fix typo
1 parent 21221ff commit b2df2a2

File tree

3 files changed

+51
-10
lines changed

3 files changed

+51
-10
lines changed

src/lib/input/input-container-errors.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,11 @@ export class MdInputContainerDuplicatedHintError extends MdError {
2020
super(`A hint was already declared for 'align="${align}"'.`);
2121
}
2222
}
23+
24+
25+
export class MdInputContainerMissingMdInputError extends MdError {
26+
constructor() {
27+
super('md-input-container must contain an md-input directive. Did you forget to add md-input ' +
28+
'to the native input or textarea element?');
29+
}
30+
}

src/lib/input/input-container.spec.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ import {MdInputModule} from './input';
66
import {MdInputContainer} from './input-container';
77
import {MdPlatform} from '../core/platform/platform';
88
import {PlatformModule} from '../core/platform/index';
9+
import {
10+
MdInputContainerMissingMdInputError,
11+
MdInputContainerPlaceholderConflictError,
12+
MdInputContainerDuplicatedHintError
13+
} from './input-container-errors';
914

1015

1116
describe('MdInputContainer', function () {
@@ -35,6 +40,7 @@ describe('MdInputContainer', function () {
3540
MdInputContainerNumberTestController,
3641
MdTextareaWithBindings,
3742
MdInputContainerWithDisabled,
43+
MdInputContainerMissingMdInputTestController
3844
],
3945
});
4046

@@ -150,25 +156,29 @@ describe('MdInputContainer', function () {
150156
it('validates there\'s only one hint label per side', () => {
151157
let fixture = TestBed.createComponent(MdInputContainerInvalidHintTestController);
152158

153-
expect(() => fixture.detectChanges()).toThrow();
154-
// TODO(jelbourn): .toThrow(new MdInputContainerDuplicatedHintError('start'));
155-
// See https://github.com/angular/angular/issues/8348
159+
expect(() => fixture.detectChanges()).toThrowError(
160+
angularWrappedErrorMessage(new MdInputContainerDuplicatedHintError('start')));
156161
});
157162

158163
it('validates there\'s only one hint label per side (attribute)', () => {
159164
let fixture = TestBed.createComponent(MdInputContainerInvalidHint2TestController);
160165

161-
expect(() => fixture.detectChanges()).toThrow();
162-
// TODO(jelbourn): .toThrow(new MdInputContainerDuplicatedHintError('start'));
163-
// See https://github.com/angular/angular/issues/8348
166+
expect(() => fixture.detectChanges()).toThrowError(
167+
angularWrappedErrorMessage(new MdInputContainerDuplicatedHintError('start')));
164168
});
165169

166170
it('validates there\'s only one placeholder', () => {
167171
let fixture = TestBed.createComponent(MdInputContainerInvalidPlaceholderTestController);
168172

169-
expect(() => fixture.detectChanges()).toThrow();
170-
// TODO(jelbourn): .toThrow(new MdInputContainerPlaceholderConflictError());
171-
// See https://github.com/angular/angular/issues/8348
173+
expect(() => fixture.detectChanges()).toThrowError(
174+
angularWrappedErrorMessage(new MdInputContainerPlaceholderConflictError()));
175+
});
176+
177+
it('validates that md-input child is present', () => {
178+
let fixture = TestBed.createComponent(MdInputContainerMissingMdInputTestController);
179+
180+
expect(() => fixture.detectChanges()).toThrowError(
181+
angularWrappedErrorMessage(new MdInputContainerMissingMdInputError()));
172182
});
173183

174184
it('validates the type', () => {
@@ -406,3 +416,21 @@ class MdTextareaWithBindings {
406416
cols: number = 8;
407417
wrap: string = 'hard';
408418
}
419+
420+
@Component({
421+
template: `<md-input-container><input></md-input-container>`
422+
})
423+
class MdInputContainerMissingMdInputTestController {}
424+
425+
/**
426+
* Gets a RegExp used to detect an angular wrapped error message.
427+
* See https://github.com/angular/angular/issues/8348
428+
*/
429+
const angularWrappedErrorMessage = (e: Error) =>
430+
new RegExp(`.*caused by: ${regexpEscape(e.message)}$`);
431+
432+
/**
433+
* Escape a string for use inside a RegExp.
434+
* Based on https://github.com/sindresorhus/escape-string-regex
435+
*/
436+
const regexpEscape = (s: string) => s.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');

src/lib/input/input-container.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ import {getSupportedInputTypes} from '../core/platform/features';
1919
import {
2020
MdInputContainerUnsupportedTypeError,
2121
MdInputContainerPlaceholderConflictError,
22-
MdInputContainerDuplicatedHintError
22+
MdInputContainerDuplicatedHintError,
23+
MdInputContainerMissingMdInputError
2324
} from './input-container-errors';
2425

2526

@@ -218,6 +219,10 @@ export class MdInputContainer implements AfterContentInit {
218219
@ContentChildren(MdHint) _hintChildren: QueryList<MdHint>;
219220

220221
ngAfterContentInit() {
222+
if (!this._mdInputChild) {
223+
throw new MdInputContainerMissingMdInputError();
224+
}
225+
221226
this._validateHints();
222227
this._validatePlaceholders();
223228

0 commit comments

Comments
 (0)