Skip to content

Commit 50548fb

Browse files
vsavkinbtford
authored andcommitted
fix(forms): use strict runtimeType checks instead of instanceof
Currently, validators extending built-in validators are treated as built-in. This can result in an error when both a real built-in validator and a custom one are applied to the same element. Closes angular#6981
1 parent 8f47aa3 commit 50548fb

File tree

4 files changed

+27
-5
lines changed

4 files changed

+27
-5
lines changed

modules/angular2/src/common/forms/directives/shared.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
2-
import {isBlank, isPresent, looseIdentical} from 'angular2/src/facade/lang';
2+
import {isBlank, isPresent, looseIdentical, hasConstructor} from 'angular2/src/facade/lang';
33
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
44

55
import {ControlContainer} from './control_container';
@@ -82,11 +82,13 @@ export function selectValueAccessor(dir: NgControl,
8282
var builtinAccessor;
8383
var customAccessor;
8484
valueAccessors.forEach(v => {
85-
if (v instanceof DefaultValueAccessor) {
85+
if (hasConstructor(v, DefaultValueAccessor)) {
8686
defaultAccessor = v;
8787

88-
} else if (v instanceof CheckboxControlValueAccessor || v instanceof NumberValueAccessor ||
89-
v instanceof SelectControlValueAccessor || v instanceof RadioControlValueAccessor) {
88+
} else if (hasConstructor(v, CheckboxControlValueAccessor) ||
89+
hasConstructor(v, NumberValueAccessor) ||
90+
hasConstructor(v, SelectControlValueAccessor) ||
91+
hasConstructor(v, RadioControlValueAccessor)) {
9092
if (isPresent(builtinAccessor))
9193
_throwError(dir, "More than one built-in value accessor matches");
9294
builtinAccessor = v;

modules/angular2/src/facade/lang.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,3 +353,7 @@ var global = null;
353353
dynamic evalExpression(String sourceUrl, String expr, String declarations, Map<String, String> vars) {
354354
throw "Dart does not support evaluating expression during runtime!";
355355
}
356+
357+
bool hasConstructor(Object value, Type type) {
358+
return value.runtimeType == type;
359+
}

modules/angular2/src/facade/lang.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,3 +464,7 @@ export function evalExpression(sourceUrl: string, expr: string, declarations: st
464464
export function isPrimitive(obj: any): boolean {
465465
return !isJsObject(obj);
466466
}
467+
468+
export function hasConstructor(value: Object, type: Type): boolean {
469+
return value.constructor === type;
470+
}

modules/angular2/test/facade/lang_spec.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@ import {
44
RegExpWrapper,
55
RegExpMatcherWrapper,
66
StringWrapper,
7-
CONST_EXPR
7+
CONST_EXPR,
8+
hasConstructor
89
} from 'angular2/src/facade/lang';
910

11+
class MySuperclass {}
12+
class MySubclass extends MySuperclass {}
13+
1014
export function main() {
1115
describe('RegExp', () => {
1216
it('should expose the index for each match', () => {
@@ -119,5 +123,13 @@ export function main() {
119123
expect(StringWrapper.stripRight(null, "S")).toEqual(null);
120124
});
121125
});
126+
127+
describe('hasConstructor', () => {
128+
it("should be true when the type matches",
129+
() => { expect(hasConstructor(new MySuperclass(), MySuperclass)).toEqual(true); });
130+
131+
it("should be false for subtypes",
132+
() => { expect(hasConstructor(new MySubclass(), MySuperclass)).toEqual(false); });
133+
});
122134
});
123135
}

0 commit comments

Comments
 (0)