fix(ivy): incorrect ChangeDetectorRef injected into pipes used in component inputs (#31438)

When injecting a `ChangeDetectorRef` into a pipe, the expected result is that the ref will be tied to the component in which the pipe is being used. This works for most cases, however when a pipe is used inside a property binding of a component (see test case as an example), the current `TNode` is pointing to component's host so we end up injecting the inner component's view. These changes fix the issue by only looking up the component view of the `TNode` if the `TNode` is a parent.

This PR resolves FW-1419.

PR Close #31438
This commit is contained in:
crisbeto
2019-07-12 20:15:12 +02:00
committed by Kara Erickson
parent f50dede8f7
commit 0aff4a6919
16 changed files with 246 additions and 30 deletions

View File

@ -2145,6 +2145,67 @@ describe('compiler compliance', () => {
expectEmit(source, MyAppDefinition, 'Invalid MyApp definition');
});
it('should generate the proper instruction when injecting ChangeDetectorRef into a pipe',
() => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule, Pipe, PipeTransform, ChangeDetectorRef, Optional} from '@angular/core';
@Pipe({name: 'myPipe'})
export class MyPipe implements PipeTransform {
constructor(changeDetectorRef: ChangeDetectorRef) {}
transform(value: any, ...args: any[]) { return value; }
}
@Pipe({name: 'myOtherPipe'})
export class MyOtherPipe implements PipeTransform {
constructor(@Optional() changeDetectorRef: ChangeDetectorRef) {}
transform(value: any, ...args: any[]) { return value; }
}
@Component({
selector: 'my-app',
template: '{{name | myPipe }}<p>{{ name | myOtherPipe }}</p>'
})
export class MyApp {
name = 'World';
}
@NgModule({declarations:[MyPipe, MyOtherPipe, MyApp]})
export class MyModule {}
`
}
};
const MyPipeDefinition = `
MyPipe.ngPipeDef = $r3$.ɵɵdefinePipe({
name: "myPipe",
type: MyPipe,
factory: function MyPipe_Factory(t) { return new (t || MyPipe)($r3$.ɵɵinjectPipeChangeDetectorRef()); },
pure: true
});
`;
const MyOtherPipeDefinition = `
MyOtherPipe.ngPipeDef = $r3$.ɵɵdefinePipe({
name: "myOtherPipe",
type: MyOtherPipe,
factory: function MyOtherPipe_Factory(t) { return new (t || MyOtherPipe)($r3$.ɵɵinjectPipeChangeDetectorRef(8)); },
pure: true
});`;
const result = compile(files, angularFiles);
const source = result.source;
expectEmit(source, MyPipeDefinition, 'Invalid pipe definition');
expectEmit(source, MyOtherPipeDefinition, 'Invalid alternate pipe definition');
});
});
it('local reference', () => {