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 #6981
This commit is contained in:
		
							parent
							
								
									8f47aa3530
								
							
						
					
					
						commit
						50548fb565
					
				| @ -1,5 +1,5 @@ | |||||||
| import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; | import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection'; | ||||||
| import {isBlank, isPresent, looseIdentical} from 'angular2/src/facade/lang'; | import {isBlank, isPresent, looseIdentical, hasConstructor} from 'angular2/src/facade/lang'; | ||||||
| import {BaseException, WrappedException} from 'angular2/src/facade/exceptions'; | import {BaseException, WrappedException} from 'angular2/src/facade/exceptions'; | ||||||
| 
 | 
 | ||||||
| import {ControlContainer} from './control_container'; | import {ControlContainer} from './control_container'; | ||||||
| @ -82,11 +82,13 @@ export function selectValueAccessor(dir: NgControl, | |||||||
|   var builtinAccessor; |   var builtinAccessor; | ||||||
|   var customAccessor; |   var customAccessor; | ||||||
|   valueAccessors.forEach(v => { |   valueAccessors.forEach(v => { | ||||||
|     if (v instanceof DefaultValueAccessor) { |     if (hasConstructor(v, DefaultValueAccessor)) { | ||||||
|       defaultAccessor = v; |       defaultAccessor = v; | ||||||
| 
 | 
 | ||||||
|     } else if (v instanceof CheckboxControlValueAccessor || v instanceof NumberValueAccessor || |     } else if (hasConstructor(v, CheckboxControlValueAccessor) || | ||||||
|                v instanceof SelectControlValueAccessor || v instanceof RadioControlValueAccessor) { |                hasConstructor(v, NumberValueAccessor) || | ||||||
|  |                hasConstructor(v, SelectControlValueAccessor) || | ||||||
|  |                hasConstructor(v, RadioControlValueAccessor)) { | ||||||
|       if (isPresent(builtinAccessor)) |       if (isPresent(builtinAccessor)) | ||||||
|         _throwError(dir, "More than one built-in value accessor matches"); |         _throwError(dir, "More than one built-in value accessor matches"); | ||||||
|       builtinAccessor = v; |       builtinAccessor = v; | ||||||
|  | |||||||
| @ -353,3 +353,7 @@ var global = null; | |||||||
| dynamic evalExpression(String sourceUrl, String expr, String declarations, Map<String, String> vars) { | dynamic evalExpression(String sourceUrl, String expr, String declarations, Map<String, String> vars) { | ||||||
|   throw "Dart does not support evaluating expression during runtime!"; |   throw "Dart does not support evaluating expression during runtime!"; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | bool hasConstructor(Object value, Type type) { | ||||||
|  |   return value.runtimeType == type; | ||||||
|  | } | ||||||
|  | |||||||
| @ -464,3 +464,7 @@ export function evalExpression(sourceUrl: string, expr: string, declarations: st | |||||||
| export function isPrimitive(obj: any): boolean { | export function isPrimitive(obj: any): boolean { | ||||||
|   return !isJsObject(obj); |   return !isJsObject(obj); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | export function hasConstructor(value: Object, type: Type): boolean { | ||||||
|  |   return value.constructor === type; | ||||||
|  | } | ||||||
| @ -4,9 +4,13 @@ import { | |||||||
|   RegExpWrapper, |   RegExpWrapper, | ||||||
|   RegExpMatcherWrapper, |   RegExpMatcherWrapper, | ||||||
|   StringWrapper, |   StringWrapper, | ||||||
|   CONST_EXPR |   CONST_EXPR, | ||||||
|  |   hasConstructor | ||||||
| } from 'angular2/src/facade/lang'; | } from 'angular2/src/facade/lang'; | ||||||
| 
 | 
 | ||||||
|  | class MySuperclass {} | ||||||
|  | class MySubclass extends MySuperclass {} | ||||||
|  | 
 | ||||||
| export function main() { | export function main() { | ||||||
|   describe('RegExp', () => { |   describe('RegExp', () => { | ||||||
|     it('should expose the index for each match', () => { |     it('should expose the index for each match', () => { | ||||||
| @ -119,5 +123,13 @@ export function main() { | |||||||
|         expect(StringWrapper.stripRight(null, "S")).toEqual(null); |         expect(StringWrapper.stripRight(null, "S")).toEqual(null); | ||||||
|       }); |       }); | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     describe('hasConstructor', () => { | ||||||
|  |       it("should be true when the type matches", | ||||||
|  |          () => { expect(hasConstructor(new MySuperclass(), MySuperclass)).toEqual(true); }); | ||||||
|  | 
 | ||||||
|  |       it("should be false for subtypes", | ||||||
|  |          () => { expect(hasConstructor(new MySubclass(), MySuperclass)).toEqual(false); }); | ||||||
|  |     }); | ||||||
|   }); |   }); | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user