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:
@ -65,6 +65,7 @@ export type Provider = any;
|
||||
export enum R3ResolvedDependencyType {
|
||||
Token = 0,
|
||||
Attribute = 1,
|
||||
ChangeDetectorRef = 2,
|
||||
}
|
||||
|
||||
export interface R3DependencyMetadataFacade {
|
||||
|
@ -33,6 +33,7 @@ export {
|
||||
RenderFlags as ɵRenderFlags,
|
||||
ɵɵdirectiveInject,
|
||||
ɵɵinjectAttribute,
|
||||
ɵɵinjectPipeChangeDetectorRef,
|
||||
ɵɵgetFactoryOf,
|
||||
ɵɵgetInheritedFactory,
|
||||
ɵɵsetComponentScope,
|
||||
|
@ -6,6 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ChangeDetectorRef} from '../../change_detection/change_detector_ref';
|
||||
import {CompilerFacade, R3DependencyMetadataFacade, getCompilerFacade} from '../../compiler/compiler_facade';
|
||||
import {Type} from '../../interface/type';
|
||||
import {ReflectionCapabilities} from '../../reflection/reflection_capabilities';
|
||||
@ -66,6 +67,9 @@ function reflectDependency(compiler: CompilerFacade, dep: any | any[]): R3Depend
|
||||
}
|
||||
meta.token = param.attributeName;
|
||||
meta.resolved = compiler.R3ResolvedDependencyType.Attribute;
|
||||
} else if (param === ChangeDetectorRef) {
|
||||
meta.token = param;
|
||||
meta.resolved = compiler.R3ResolvedDependencyType.ChangeDetectorRef;
|
||||
} else {
|
||||
setTokenAndResolvedType(param);
|
||||
}
|
||||
|
@ -6,10 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {InjectFlags, InjectionToken} from '../di';
|
||||
import {InjectionToken} from '../di/injection_token';
|
||||
import {Injector} from '../di/injector';
|
||||
import {injectRootLimpMode, setInjectImplementation} from '../di/injector_compatibility';
|
||||
import {getInjectableDef, getInjectorDef} from '../di/interface/defs';
|
||||
import {InjectFlags} from '../di/interface/injector';
|
||||
import {Type} from '../interface/type';
|
||||
import {assertDefined, assertEqual} from '../util/assert';
|
||||
|
||||
|
@ -198,7 +198,7 @@ export {
|
||||
ɵɵpureFunctionV,
|
||||
} from './pure_function';
|
||||
|
||||
export {ɵɵtemplateRefExtractor} from './view_engine_compatibility_prebound';
|
||||
export {ɵɵtemplateRefExtractor, ɵɵinjectPipeChangeDetectorRef} from './view_engine_compatibility_prebound';
|
||||
|
||||
export {ɵɵresolveWindow, ɵɵresolveDocument, ɵɵresolveBody} from './util/misc_utils';
|
||||
|
||||
|
@ -42,6 +42,7 @@ export const angularCoreEnv: {[name: string]: Function} =
|
||||
'ɵɵgetInheritedFactory': r3.ɵɵgetInheritedFactory,
|
||||
'ɵɵinject': ɵɵinject,
|
||||
'ɵɵinjectAttribute': r3.ɵɵinjectAttribute,
|
||||
'ɵɵinjectPipeChangeDetectorRef': r3.ɵɵinjectPipeChangeDetectorRef,
|
||||
'ɵɵtemplateRefExtractor': r3.ɵɵtemplateRefExtractor,
|
||||
'ɵɵNgOnChangesFeature': r3.ɵɵNgOnChangesFeature,
|
||||
'ɵɵProvidersFeature': r3.ɵɵProvidersFeature,
|
||||
|
@ -362,8 +362,8 @@ export function createContainerRef(
|
||||
|
||||
|
||||
/** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */
|
||||
export function injectChangeDetectorRef(): ViewEngine_ChangeDetectorRef {
|
||||
return createViewRef(getPreviousOrParentTNode(), getLView(), null);
|
||||
export function injectChangeDetectorRef(isPipe = false): ViewEngine_ChangeDetectorRef {
|
||||
return createViewRef(getPreviousOrParentTNode(), getLView(), isPipe);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -371,15 +371,15 @@ export function injectChangeDetectorRef(): ViewEngine_ChangeDetectorRef {
|
||||
*
|
||||
* @param hostTNode The node that is requesting a ChangeDetectorRef
|
||||
* @param hostView The view to which the node belongs
|
||||
* @param context The context for this change detector ref
|
||||
* @param isPipe Whether the view is being injected into a pipe.
|
||||
* @returns The ChangeDetectorRef to use
|
||||
*/
|
||||
export function createViewRef(
|
||||
hostTNode: TNode, hostView: LView, context: any): ViewEngine_ChangeDetectorRef {
|
||||
if (isComponent(hostTNode)) {
|
||||
function createViewRef(
|
||||
hostTNode: TNode, hostView: LView, isPipe: boolean): ViewEngine_ChangeDetectorRef {
|
||||
if (isComponent(hostTNode) && !isPipe) {
|
||||
const componentIndex = hostTNode.directiveStart;
|
||||
const componentView = getComponentViewByIndex(hostTNode.index, hostView);
|
||||
return new ViewRef(componentView, context, componentIndex);
|
||||
return new ViewRef(componentView, null, componentIndex);
|
||||
} else if (
|
||||
hostTNode.type === TNodeType.Element || hostTNode.type === TNodeType.Container ||
|
||||
hostTNode.type === TNodeType.ElementContainer) {
|
||||
|
@ -7,12 +7,14 @@
|
||||
*/
|
||||
|
||||
|
||||
import {ChangeDetectorRef} from '../change_detection/change_detector_ref';
|
||||
import {InjectFlags} from '../di/interface/injector';
|
||||
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
|
||||
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
|
||||
|
||||
import {TNode} from './interfaces/node';
|
||||
import {LView} from './interfaces/view';
|
||||
import {createTemplateRef} from './view_engine_compatibility';
|
||||
import {createTemplateRef, injectChangeDetectorRef} from './view_engine_compatibility';
|
||||
|
||||
|
||||
|
||||
@ -25,3 +27,18 @@ import {createTemplateRef} from './view_engine_compatibility';
|
||||
export function ɵɵtemplateRefExtractor(tNode: TNode, currentView: LView) {
|
||||
return createTemplateRef(ViewEngine_TemplateRef, ViewEngine_ElementRef, tNode, currentView);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the appropriate `ChangeDetectorRef` for a pipe.
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵinjectPipeChangeDetectorRef(flags = InjectFlags.Default): ChangeDetectorRef|null {
|
||||
const value = injectChangeDetectorRef(true);
|
||||
if (value == null && !(flags & InjectFlags.Optional)) {
|
||||
throw new Error(`No provider for ChangeDetectorRef!`);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user