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 RElement).setProperty ? (element as any).setProperty(propName, value) :
|
||||||
(element as any)[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...
|
// and isn't a synthetic animation property...
|
||||||
propName[0] !== ANIMATION_PROP_PREFIX) {
|
propName[0] !== ANIMATION_PROP_PREFIX) {
|
||||||
// ... it is probably a user error and we should throw.
|
// ... it is probably a user error and we should throw.
|
||||||
throw new Error(
|
throw createUnknownPropertyError(propName, tNode);
|
||||||
`Template error: Can't bind to '${propName}' since it isn't a known property of '${tNode.tagName}'.`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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',
|
it('should not throw for property binding to a non-existing property when there is a matching directive property',
|
||||||
() => {
|
() => {
|
||||||
TestBed.configureTestingModule({declarations: [MyComp, MyDir]});
|
TestBed.configureTestingModule({declarations: [MyComp, MyDir]});
|
||||||
|
@ -2103,12 +2118,14 @@ class MyComp {
|
||||||
ctxProp: string;
|
ctxProp: string;
|
||||||
ctxNumProp: number;
|
ctxNumProp: number;
|
||||||
ctxBoolProp: boolean;
|
ctxBoolProp: boolean;
|
||||||
|
ctxArrProp: number[];
|
||||||
toStringThrow = {toString: function() { throw 'boom'; }};
|
toStringThrow = {toString: function() { throw 'boom'; }};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.ctxProp = 'initial value';
|
this.ctxProp = 'initial value';
|
||||||
this.ctxNumProp = 0;
|
this.ctxNumProp = 0;
|
||||||
this.ctxBoolProp = false;
|
this.ctxBoolProp = false;
|
||||||
|
this.ctxArrProp = [0, 1, 2];
|
||||||
}
|
}
|
||||||
|
|
||||||
throwError() { throw 'boom'; }
|
throwError() { throw 'boom'; }
|
||||||
|
|
Loading…
Reference in New Issue