fix(ivy): not throwing error for unknown properties on container nodes (#29691)
Fixes Ivy not throwing an error if it runs into an invalid property binding on a container node (e.g. `<div *ngFor="let row of rows">` instead of `<div *ngFor="let row if rows">`). This PR resolves FW-1219. PR Close #29691
This commit is contained in:
parent
66b87cef33
commit
d144a3bd91
|
@ -161,6 +161,12 @@ function elementPropertyInternal<T>(
|
|||
(element as RElement).setProperty ? (element as any).setProperty(propName, value) :
|
||||
(element as any)[propName] = value;
|
||||
}
|
||||
} else if (tNode.type === TNodeType.Container) {
|
||||
// If the node is a container and the property didn't
|
||||
// match any of the inputs or schemas we should throw.
|
||||
if (ngDevMode && !matchingSchemas(lView, tNode.tagName)) {
|
||||
throw createUnknownPropertyError(propName, tNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,8 +215,7 @@ function validateAgainstUnknownProperties(
|
|||
// and isn't a synthetic animation property...
|
||||
propName[0] !== ANIMATION_PROP_PREFIX) {
|
||||
// ... it is probably a user error and we should throw.
|
||||
throw new Error(
|
||||
`Template error: Can't bind to '${propName}' since it isn't a known property of '${tNode.tagName}'.`);
|
||||
throw createUnknownPropertyError(propName, tNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,3 +262,13 @@ function savePropertyDebugData(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an error that should be thrown when encountering an unknown property on an element.
|
||||
* @param propName Name of the invalid property.
|
||||
* @param tNode Node on which we encountered the error.
|
||||
*/
|
||||
function createUnknownPropertyError(propName: string, tNode: TNode): Error {
|
||||
return new Error(
|
||||
`Template error: Can't bind to '${propName}' since it isn't a known property of '${tNode.tagName}'.`);
|
||||
}
|
||||
|
|
|
@ -1634,6 +1634,21 @@ function declareTests(config?: {useJit: boolean}) {
|
|||
}
|
||||
});
|
||||
|
||||
it('should throw on bindings to unknown properties of containers', () => {
|
||||
TestBed.configureTestingModule({imports: [CommonModule], declarations: [MyComp]});
|
||||
const template = '<div *ngFor="let item in ctxArrProp">{{item}}</div>';
|
||||
TestBed.overrideComponent(MyComp, {set: {template}});
|
||||
|
||||
try {
|
||||
const fixture = TestBed.createComponent(MyComp);
|
||||
fixture.detectChanges();
|
||||
throw 'Should throw';
|
||||
} catch (e) {
|
||||
expect(e.message).toMatch(
|
||||
/Can't bind to 'ngForIn' since it isn't a known property of 'div'./);
|
||||
}
|
||||
});
|
||||
|
||||
it('should not throw for property binding to a non-existing property when there is a matching directive property',
|
||||
() => {
|
||||
TestBed.configureTestingModule({declarations: [MyComp, MyDir]});
|
||||
|
@ -2103,12 +2118,14 @@ class MyComp {
|
|||
ctxProp: string;
|
||||
ctxNumProp: number;
|
||||
ctxBoolProp: boolean;
|
||||
ctxArrProp: number[];
|
||||
toStringThrow = {toString: function() { throw 'boom'; }};
|
||||
|
||||
constructor() {
|
||||
this.ctxProp = 'initial value';
|
||||
this.ctxNumProp = 0;
|
||||
this.ctxBoolProp = false;
|
||||
this.ctxArrProp = [0, 1, 2];
|
||||
}
|
||||
|
||||
throwError() { throw 'boom'; }
|
||||
|
|
Loading…
Reference in New Issue