fix(ivy): objects like ElementRef should not use a special injection fn (#26064)

PR Close #26064
This commit is contained in:
Kara Erickson 2018-09-21 18:38:13 -07:00
parent 482e12c940
commit 6a62ed2245
56 changed files with 1367 additions and 1073 deletions

View File

@ -68,21 +68,9 @@ export function getConstructorDependencies(
const importedSymbol = reflector.getImportOfIdentifier(tokenExpr);
if (importedSymbol !== null && importedSymbol.from === '@angular/core') {
switch (importedSymbol.name) {
case 'ChangeDetectorRef':
resolved = R3ResolvedDependencyType.ChangeDetectorRef;
break;
case 'ElementRef':
resolved = R3ResolvedDependencyType.ElementRef;
break;
case 'Injector':
resolved = R3ResolvedDependencyType.Injector;
break;
case 'TemplateRef':
resolved = R3ResolvedDependencyType.TemplateRef;
break;
case 'ViewContainerRef':
resolved = R3ResolvedDependencyType.ViewContainerRef;
break;
case 'Renderer2':
resolved = R3ResolvedDependencyType.Renderer2;
break;

View File

@ -648,6 +648,49 @@ describe('compiler compliance', () => {
expectEmit(source, HostBindingCompDeclaration, 'Invalid host binding code');
});
it('should not treat ElementRef, ViewContainerRef, or ChangeDetectorRef specially when injecting',
() => {
const files = {
app: {
'spec.ts': `
import {Component, NgModule, ElementRef, ChangeDetectorRef, ViewContainerRef} from '@angular/core';
@Component({
selector: 'my-component',
template: ''
})
export class MyComponent {
constructor(public el: ElementRef, public vcr: ViewContainerRef, public cdr: ChangeDetectorRef) {}
}
@NgModule({declarations: [MyComponent]})
export class MyModule {}
`
}
};
const MyComponentDefinition = `
MyComponent.ngComponentDef = $r3$.ɵdefineComponent({
type: MyComponent,
selectors: [["my-component"]],
factory: function MyComponent_Factory(t) {
return new (t || MyComponent)(
$r3$.ɵdirectiveInject(ElementRef), $r3$.ɵdirectiveInject(ViewContainerRef),
$r3$.ɵdirectiveInject(ChangeDetectorRef));
},
features: [$r3$.ɵPublicFeature],
consts: 0,
vars: 0,
template: function MyComponent_Template(rf, ctx) {}
});`;
const result = compile(files, angularFiles);
const source = result.source;
expectEmit(source, MyComponentDefinition, 'Incorrect MyComponent.ngComponentDef');
});
it('should support structural directives', () => {
const files = {
app: {
@ -677,7 +720,7 @@ describe('compiler compliance', () => {
IfDirective.ngDirectiveDef = $r3$.ɵdefineDirective({
type: IfDirective,
selectors: [["", "if", ""]],
factory: function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵinjectTemplateRef()); },
factory: function IfDirective_Factory(t) { return new (t || IfDirective)($r3$.ɵdirectiveInject(TemplateRef)); },
features: [$r3$.ɵPublicFeature]
});`;
const MyComponentDefinition = `
@ -1703,7 +1746,7 @@ describe('compiler compliance', () => {
type: ForOfDirective,
selectors: [["", "forOf", ""]],
factory: function ForOfDirective_Factory(t) {
return new (t || ForOfDirective)($r3$.ɵinjectViewContainerRef(), $r3$.ɵinjectTemplateRef());
return new (t || ForOfDirective)($r3$.ɵdirectiveInject(ViewContainerRef), $r3$.ɵdirectiveInject(TemplateRef));
},
features: [$r3$.ɵPublicFeature, $r3$.ɵNgOnChangesFeature],
inputs: {forOf: "forOf"}
@ -1779,7 +1822,7 @@ describe('compiler compliance', () => {
type: ForOfDirective,
selectors: [["", "forOf", ""]],
factory: function ForOfDirective_Factory(t) {
return new (t || ForOfDirective)($r3$.ɵinjectViewContainerRef(), $r3$.ɵinjectTemplateRef());
return new (t || ForOfDirective)($r3$.ɵdirectiveInject(ViewContainerRef), $r3$.ɵdirectiveInject(TemplateRef));
},
features: [$r3$.ɵPublicFeature, $r3$.ɵNgOnChangesFeature],
inputs: {forOf: "forOf"}

View File

@ -480,7 +480,7 @@ describe('ngtsc behavioral tests', () => {
const jsContents = getContents('test.js');
expect(jsContents)
.toContain(
`factory: function FooCmp_Factory(t) { return new (t || FooCmp)(i0.ɵinjectAttribute("test"), i0.ɵinjectChangeDetectorRef(), i0.ɵinjectElementRef(), i0.ɵdirectiveInject(i0.INJECTOR), i0.ɵinjectRenderer2(), i0.ɵinjectTemplateRef(), i0.ɵinjectViewContainerRef()); }`);
`factory: function FooCmp_Factory(t) { return new (t || FooCmp)(i0.ɵinjectAttribute("test"), i0.ɵdirectiveInject(ChangeDetectorRef), i0.ɵdirectiveInject(ElementRef), i0.ɵdirectiveInject(i0.INJECTOR), i0.ɵinjectRenderer2(), i0.ɵdirectiveInject(TemplateRef), i0.ɵdirectiveInject(ViewContainerRef)); }`);
});
it('should generate queries for components', () => {

View File

@ -101,30 +101,10 @@ export enum R3ResolvedDependencyType {
*/
Injector = 2,
/**
* The dependency is for `ElementRef`.
*/
ElementRef = 3,
/**
* The dependency is for `TemplateRef`.
*/
TemplateRef = 4,
/**
* The dependency is for `ViewContainerRef`.
*/
ViewContainerRef = 5,
/**
* The dependency is for `ChangeDetectorRef`.
*/
ChangeDetectorRef = 6,
/**
* The dependency is for `Renderer2`.
*/
Renderer2 = 7,
Renderer2 = 3,
}
/**
@ -282,14 +262,6 @@ function compileInjectDependency(
case R3ResolvedDependencyType.Attribute:
// In the case of attributes, the attribute name in question is given as the token.
return o.importExpr(R3.injectAttribute).callFn([dep.token]);
case R3ResolvedDependencyType.ElementRef:
return o.importExpr(R3.injectElementRef).callFn([]);
case R3ResolvedDependencyType.TemplateRef:
return o.importExpr(R3.injectTemplateRef).callFn([]);
case R3ResolvedDependencyType.ViewContainerRef:
return o.importExpr(R3.injectViewContainerRef).callFn([]);
case R3ResolvedDependencyType.ChangeDetectorRef:
return o.importExpr(R3.injectChangeDetectorRef).callFn([]);
case R3ResolvedDependencyType.Renderer2:
return o.importExpr(R3.injectRenderer2).callFn([]);
default:
@ -320,13 +292,7 @@ export function dependenciesFromGlobalMetadata(
if (dependency.token) {
const tokenRef = tokenReference(dependency.token);
let resolved: R3ResolvedDependencyType = R3ResolvedDependencyType.Token;
if (tokenRef === elementRef) {
resolved = R3ResolvedDependencyType.ElementRef;
} else if (tokenRef === templateRef) {
resolved = R3ResolvedDependencyType.TemplateRef;
} else if (tokenRef === viewContainerRef) {
resolved = R3ResolvedDependencyType.ViewContainerRef;
} else if (tokenRef === injectorRef) {
if (tokenRef === injectorRef) {
resolved = R3ResolvedDependencyType.Injector;
} else if (tokenRef === renderer2) {
resolved = R3ResolvedDependencyType.Renderer2;
@ -363,4 +329,4 @@ function isDelegatedMetadata(meta: R3FactoryMetadata): meta is R3DelegatedFactor
function isExpressionFactoryMetadata(meta: R3FactoryMetadata): meta is R3ExpressionFactoryMetadata {
return (meta as any).expression !== undefined;
}
}

View File

@ -106,16 +106,6 @@ export class Identifiers {
static injectAttribute: o.ExternalReference = {name: 'ɵinjectAttribute', moduleName: CORE};
static injectElementRef: o.ExternalReference = {name: 'ɵinjectElementRef', moduleName: CORE};
static injectTemplateRef: o.ExternalReference = {name: 'ɵinjectTemplateRef', moduleName: CORE};
static injectViewContainerRef:
o.ExternalReference = {name: 'ɵinjectViewContainerRef', moduleName: CORE};
static injectChangeDetectorRef:
o.ExternalReference = {name: 'ɵinjectChangeDetectorRef', moduleName: CORE};
static injectRenderer2: o.ExternalReference = {name: 'ɵinjectRenderer2', moduleName: CORE};
static directiveInject: o.ExternalReference = {name: 'ɵdirectiveInject', moduleName: CORE};

View File

@ -43,7 +43,7 @@ function baseDirectiveFields(
definitionMap.set('selectors', createDirectiveSelector(meta.selector !));
// e.g. `factory: () => new MyApp(injectElementRef())`
// e.g. `factory: () => new MyApp(directiveInject(ElementRef))`
const result = compileFactoryFunction({
name: meta.name,
type: meta.type,

View File

@ -9,9 +9,13 @@ ng_module(
"*.ts",
"src/**/*.ts",
],
exclude = ["src/ivy_switch.ts"],
exclude = [
"src/ivy_switch/compiler/index.ts",
"src/ivy_switch/runtime/index.ts",
],
) + [
":ivy_switch",
":ivy_switch_compiler",
":ivy_switch_runtime",
],
module_name = "@angular/core",
deps = [
@ -42,19 +46,27 @@ ng_package(
## Controls if Ivy is enabled. (Temporary target until we permanently switch over to Ivy)
##
## This file generates `src/ivy_switch.ts` file which reexports symbols for `ViewEngine` or `Ivy.`
## - append `--define=compile=legacy` (default) to `bazel` command to reexport `./ivy_switch_legacy`
## and use `ViewEngine`
## - append `--define=compile=jit` to `bazel` command to rexport `./ivy_switch_jit` and use `Ivy`
## - append `--define=compile=local` to `bazel` command to rexport `./ivy_switch_jit` and use `Ivy`
## This file generates the `src/ivy_switch/compiler/index.ts` and `src/ivy_switch/runtime/index.ts` files which
## reexport symbols for `ViewEngine` or `Ivy.`
## - append `--define=compile=legacy` (default) to `bazel` command to reexport `./legacy` from each folder
## in the 'ivy_switch' directory and use `ViewEngine`
## - append `--define=compile=jit` to `bazel` command to rexport `./jit` from each folder in the `ivy_switch`
## directory and use `Ivy`
## - append `--define=compile=local` to `bazel` command to rexport `./ivy_switch/compiler/jit` and use `Ivy`
## in the local analysis mode. (run as part of `ngtsc`)
##
## NOTE: `--define=compile=jit` works with any `bazel` command or target across the repo.
##
## See: `//tools/bazel.rc` where `--define=ivy=false` is defined as default.
## See: `./src/ivy_switch.ts` for more details.
## See: `./src/ivy_switch/compiler/index.ts` for more details.
genrule(
name = "ivy_switch",
outs = ["src/ivy_switch.ts"],
cmd = "echo export '*' from \"'./ivy_switch_$(compile)';\" > $@",
name = "ivy_switch_compiler",
outs = ["src/ivy_switch/compiler/index.ts"],
cmd = "echo export '*' from \"'./$(compile)';\" > $@",
)
genrule(
name = "ivy_switch_runtime",
outs = ["src/ivy_switch/runtime/index.ts"],
cmd = "echo export '*' from \"'./$(compile)';\" > $@",
)

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {R3_CHANGE_DETECTOR_REF_FACTORY} from '../ivy_switch/runtime/index';
/**
* Base class for Angular Views, provides change detection functionality.
* A change-detection tree collects all views that are to be checked for changes.
@ -103,4 +105,7 @@ export abstract class ChangeDetectorRef {
*
*/
abstract reattach(): void;
/** @internal */
static __NG_ELEMENT_ID__: () => ChangeDetectorRef = () => R3_CHANGE_DETECTOR_REF_FACTORY();
}

View File

@ -16,7 +16,7 @@ export {Console as ɵConsole} from './console';
export {InjectableDef as ɵInjectableDef, InjectorDef as ɵInjectorDef, getInjectableDef as ɵgetInjectableDef} from './di/defs';
export {inject as ɵinject, setCurrentInjector as ɵsetCurrentInjector} from './di/injector';
export {APP_ROOT as ɵAPP_ROOT} from './di/scope';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch';
export {ivyEnabled as ɵivyEnabled} from './ivy_switch/compiler/index';
export {ComponentFactory as ɵComponentFactory} from './linker/component_factory';
export {CodegenComponentFactoryResolver as ɵCodegenComponentFactoryResolver} from './linker/component_factory_resolver';
export {resolveComponentResources as ɵresolveComponentResources} from './metadata/resource_loading';

View File

@ -21,10 +21,6 @@ export {
DirectiveType as ɵDirectiveType,
RenderFlags as ɵRenderFlags,
directiveInject as ɵdirectiveInject,
injectElementRef as ɵinjectElementRef,
injectTemplateRef as ɵinjectTemplateRef,
injectViewContainerRef as ɵinjectViewContainerRef,
injectChangeDetectorRef as ɵinjectChangeDetectorRef,
injectRenderer2 as ɵinjectRenderer2,
injectAttribute as ɵinjectAttribute,
getFactoryOf as ɵgetFactoryOf,
@ -187,6 +183,15 @@ export {
R3_COMPILE_INJECTABLE__POST_NGCC__ as ɵR3_COMPILE_INJECTABLE__POST_NGCC__,
R3_COMPILE_NGMODULE__POST_NGCC__ as ɵR3_COMPILE_NGMODULE__POST_NGCC__,
R3_COMPILE_PIPE__POST_NGCC__ as ɵR3_COMPILE_PIPE__POST_NGCC__,
ivyEnable__POST_NGCC__ as ɵivyEnable__POST_NGCC__
} from './ivy_switch_legacy';
ivyEnable__POST_NGCC__ as ɵivyEnable__POST_NGCC__,
} from './ivy_switch/compiler/legacy';
export {
R3_ELEMENT_REF_FACTORY__POST_NGCC__ as ɵR3_ELEMENT_REF_FACTORY__POST_NGCC__,
R3_TEMPLATE_REF_FACTORY__POST_NGCC__ as ɵR3_TEMPLATE_REF_FACTORY__POST_NGCC__,
R3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__ as ɵR3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__,
R3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__ as ɵR3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__,
} from './ivy_switch/runtime/legacy';
// clang-format on

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {R3_COMPILE_INJECTABLE} from '../ivy_switch';
import {R3_COMPILE_INJECTABLE} from '../ivy_switch/compiler/index';
import {Type} from '../type';
import {makeDecorator} from '../util/decorators';

View File

@ -12,6 +12,6 @@
* For more information on how to run and debug tests with either Ivy or View Engine (legacy),
* please see [BAZEL.md](./docs/BAZEL.md).
*/
export * from './ivy_switch_legacy';
export * from './legacy';
// TODO(alxhub): debug why metadata doesn't properly propagate through this file.

View File

@ -6,10 +6,10 @@
* found in the LICENSE file at https://angular.io/license
*/
import {compileComponent, compileDirective} from './render3/jit/directive';
import {compileInjectable} from './render3/jit/injectable';
import {compileNgModule} from './render3/jit/module';
import {compilePipe} from './render3/jit/pipe';
import {compileComponent, compileDirective} from '../../render3/jit/directive';
import {compileInjectable} from '../../render3/jit/injectable';
import {compileNgModule} from '../../render3/jit/module';
import {compilePipe} from '../../render3/jit/pipe';
export const ivyEnabled = true;
export const R3_COMPILE_COMPONENT = compileComponent;

View File

@ -6,15 +6,16 @@
* found in the LICENSE file at https://angular.io/license
*/
import {InjectableType, InjectorType, defineInjectable, defineInjector, getInjectableDef} from './di/defs';
import {InjectableProvider} from './di/injectable';
import {inject, injectArgs} from './di/injector';
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from './di/provider';
import {InjectableType, InjectorType, defineInjectable, defineInjector, getInjectableDef} from '../../di/defs';
import {InjectableProvider} from '../../di/injectable';
import {inject, injectArgs} from '../../di/injector';
import {ClassSansProvider, ConstructorSansProvider, ExistingSansProvider, FactorySansProvider, StaticClassSansProvider, ValueProvider, ValueSansProvider} from '../../di/provider';
import {NgModule} from '../../metadata';
import {ReflectionCapabilities} from '../../reflection/reflection_capabilities';
import {Type} from '../../type';
import {getClosureSafeProperty} from '../../util/property';
import * as ivyOn from './ivy_switch_on';
import {NgModule} from './metadata';
import {ReflectionCapabilities} from './reflection/reflection_capabilities';
import {Type} from './type';
import {getClosureSafeProperty} from './util/property';
function noop() {}
@ -25,6 +26,7 @@ export const R3_COMPILE_DIRECTIVE__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COM
export const R3_COMPILE_INJECTABLE__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COMPILE_INJECTABLE;
export const R3_COMPILE_NGMODULE__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COMPILE_NGMODULE;
export const R3_COMPILE_PIPE__POST_NGCC__: DirectiveCompiler = ivyOn.R3_COMPILE_PIPE;
export const ivyEnable__POST_NGCC__: boolean = ivyOn.ivyEnabled;
const R3_COMPILE_COMPONENT__PRE_NGCC__: DirectiveCompiler = noop;
@ -32,6 +34,7 @@ const R3_COMPILE_DIRECTIVE__PRE_NGCC__: DirectiveCompiler = noop;
const R3_COMPILE_INJECTABLE__PRE_NGCC__: DirectiveCompiler = preR3InjectableCompile;
const R3_COMPILE_NGMODULE__PRE_NGCC__: DirectiveCompiler = preR3NgModuleCompile;
const R3_COMPILE_PIPE__PRE_NGCC__: DirectiveCompiler = noop;
const ivyEnable__PRE_NGCC__ = false;
export const ivyEnabled = ivyEnable__PRE_NGCC__;
@ -111,4 +114,4 @@ function preR3InjectableCompile(
factory: convertInjectableProviderToFactory(injectableType, options),
});
}
}
}

View File

@ -0,0 +1,15 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* This file is used to control if the default rendering pipeline should be `ViewEngine` or `Ivy`.
*
* For more information on how to run and debug tests with either Ivy or View Engine (legacy),
* please see [BAZEL.md](./docs/BAZEL.md).
*/
export * from './legacy';

View File

@ -0,0 +1,14 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {injectChangeDetectorRef, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../render3/view_engine_compatibility';
export const R3_ELEMENT_REF_FACTORY = injectElementRef;
export const R3_TEMPLATE_REF_FACTORY = injectTemplateRef;
export const R3_CHANGE_DETECTOR_REF_FACTORY = injectChangeDetectorRef;
export const R3_VIEW_CONTAINER_REF_FACTORY = injectViewContainerRef;

View File

@ -0,0 +1,10 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export * from './ivy_switch_on';

View File

@ -0,0 +1,31 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import * as ivyOn from './ivy_switch_on';
function noopFactory(...tokens: any[]): any {}
type FactoryFunction<T = any> = (...tokens: any[]) => T;
export const R3_ELEMENT_REF_FACTORY__POST_NGCC__: FactoryFunction = ivyOn.R3_ELEMENT_REF_FACTORY;
export const R3_TEMPLATE_REF_FACTORY__POST_NGCC__: FactoryFunction = ivyOn.R3_TEMPLATE_REF_FACTORY;
export const R3_CHANGE_DETECTOR_REF_FACTORY__POST_NGCC__: FactoryFunction =
ivyOn.R3_CHANGE_DETECTOR_REF_FACTORY;
export const R3_VIEW_CONTAINER_REF_FACTORY__POST_NGCC__: FactoryFunction =
ivyOn.R3_VIEW_CONTAINER_REF_FACTORY;
export const R3_ELEMENT_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_TEMPLATE_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_CHANGE_DETECTOR_REF_FACTORY__PRE_NGCC__ = noopFactory;
export const R3_VIEW_CONTAINER_REF_FACTORY__PRE_NGCC__ = noopFactory;
export let R3_ELEMENT_REF_FACTORY = R3_ELEMENT_REF_FACTORY__PRE_NGCC__;
export let R3_TEMPLATE_REF_FACTORY = R3_TEMPLATE_REF_FACTORY__PRE_NGCC__;
export let R3_CHANGE_DETECTOR_REF_FACTORY = R3_CHANGE_DETECTOR_REF_FACTORY__PRE_NGCC__;
export let R3_VIEW_CONTAINER_REF_FACTORY = R3_VIEW_CONTAINER_REF_FACTORY__PRE_NGCC__;

View File

@ -0,0 +1,10 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
export * from './ivy_switch_on';

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {R3_ELEMENT_REF_FACTORY} from '../ivy_switch/runtime/index';
/**
* A wrapper around a native element inside of a View.
*
@ -46,4 +48,7 @@ export class ElementRef<T = any> {
public nativeElement: T;
constructor(nativeElement: T) { this.nativeElement = nativeElement; }
/** @internal */
static __NG_ELEMENT_ID__: () => ElementRef = () => R3_ELEMENT_REF_FACTORY(ElementRef);
}

View File

@ -6,6 +6,8 @@
* found in the LICENSE file at https://angular.io/license
*/
import {R3_TEMPLATE_REF_FACTORY} from '../ivy_switch/runtime/index';
import {ElementRef} from './element_ref';
import {EmbeddedViewRef} from './view_ref';
@ -14,12 +16,12 @@ import {EmbeddedViewRef} from './view_ref';
* Represents an embedded template that can be used to instantiate embedded views.
* To instantiate embedded views based on a template, use the `ViewContainerRef`
* method `createEmbeddedView()`.
*
*
* Access a `TemplateRef` instance by placing a directive on an `<ng-template>`
* element (or directive prefixed with `*`). The `TemplateRef` for the embedded view
* is injected into the constructor of the directive,
* using the `TemplateRef` token.
*
*
* You can also use a `Query` to find a `TemplateRef` associated with
* a component or a directive.
*
@ -48,4 +50,8 @@ export abstract class TemplateRef<C> {
* @returns The new view object.
*/
abstract createEmbeddedView(context: C): EmbeddedViewRef<C>;
/** @internal */
static __NG_ELEMENT_ID__:
() => TemplateRef<any> = () => R3_TEMPLATE_REF_FACTORY(TemplateRef, ElementRef)
}

View File

@ -7,6 +7,8 @@
*/
import {Injector} from '../di/injector';
import {R3_VIEW_CONTAINER_REF_FACTORY} from '../ivy_switch/runtime/index';
import {ComponentFactory, ComponentRef} from './component_factory';
import {ElementRef} from './element_ref';
import {NgModuleRef} from './ng_module_factory';
@ -139,4 +141,8 @@ export abstract class ViewContainerRef {
* If not specified, the last view in the container is detached.
*/
abstract detach(index?: number): ViewRef|null;
/** @internal */
static __NG_ELEMENT_ID__:
() => ViewContainerRef = () => R3_VIEW_CONTAINER_REF_FACTORY(ViewContainerRef, ElementRef)
}

View File

@ -8,7 +8,7 @@
import {ChangeDetectionStrategy} from '../change_detection/constants';
import {Provider} from '../di';
import {R3_COMPILE_COMPONENT, R3_COMPILE_DIRECTIVE, R3_COMPILE_PIPE} from '../ivy_switch';
import {R3_COMPILE_COMPONENT, R3_COMPILE_DIRECTIVE, R3_COMPILE_PIPE} from '../ivy_switch/compiler/index';
import {NG_BASE_DEF} from '../render3/fields';
import {Type} from '../type';
import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators';

View File

@ -8,7 +8,7 @@
import {ApplicationRef} from '../application_ref';
import {Provider} from '../di/provider';
import {R3_COMPILE_NGMODULE} from '../ivy_switch';
import {R3_COMPILE_NGMODULE} from '../ivy_switch/compiler/index';
import {Type} from '../type';
import {TypeDecorator, makeDecorator} from '../util/decorators';

View File

@ -382,17 +382,19 @@ NOTE:
An interesting thing about these objects is that they are not memoized `injector.get(ElementRef) !== injector.get(ElementRef)`.
This could be considered a bug, it means that we don't have to allocate storage space for them.
We should treat these special objects like any other token. `directiveInject()` already reads a special `NG_ELEMENT_ID`
property set on directives to locate their bit in the bloom filter. We can set this same property on special objects,
but point to a factory function rather than an element ID number. When we check that property in `directiveInject()`
and see that it's a function, we know to invoke the factory function directly instead of searching the node tree.
```typescript
@Injectable({
provideIn: '__node__' as any // Special token not available to the developer
useFactory: injectElementRef // existing function which generates ElementRef
})
class ElementRef {
...
static __NG_ELEMENT_ID__ = () => injectElementRef();
}
```
Consequence of the above is that `injector.get(ElementRef)` returns an instance of `ElementRef` without `Injector` having to know about `ElementRef` at compile time.
Consequence of the above is that `directiveInject(ElementRef)` returns an instance of `ElementRef` without `Injector` having to know about `ElementRef` at compile time.
# `EXPANDO` and Injecting the `Injector`.
@ -421,10 +423,7 @@ function inject(token: any): any {
let injectableDef;
if (typeof token === 'function' && injectableDef = token.ngInjectableDef) {
const provideIn = injectableDef.provideIn;
if (provideIn === '__node__') {
// if it is a special object just call its factory
return injectableDef.useFactory();
} else if (provideIn === '__node_injector__') {
if (provideIn === '__node_injector__') {
// if we are injecting `Injector` than create a wrapper object around the inject but which
// is bound to the current node.
return createInjector();

View File

@ -24,6 +24,7 @@ import {ComponentDefInternal, RenderFlags} from './interfaces/definition';
import {LElementNode, TElementNode, TNode, TNodeType, TViewNode} from './interfaces/node';
import {RElement, RendererFactory3, domRendererFactory3} from './interfaces/renderer';
import {FLAGS, INJECTOR, LViewData, LViewFlags, RootContext, TVIEW} from './interfaces/view';
import {createElementRef} from './view_engine_compatibility';
import {RootViewRef, ViewRef} from './view_ref';
export class ComponentFactoryResolver extends viewEngine_ComponentFactoryResolver {
@ -176,8 +177,10 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
if (rendererFactory.end) rendererFactory.end();
}
const componentRef =
new ComponentRef(this.componentType, component, rootView, injector, hostNode !);
const componentRef = new ComponentRef(
this.componentType, component, rootView, injector,
createElementRef(viewEngine_ElementRef, tElementNode, rootView));
if (isInternalRootView) {
// The host element of the internal root view is attached to the component's host view node
componentRef.hostView._tViewNode !.child = tElementNode;
@ -186,6 +189,19 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
}
}
const componentFactoryResolver: ComponentFactoryResolver = new ComponentFactoryResolver();
/**
* Creates a ComponentFactoryResolver and stores it on the injector. Or, if the
* ComponentFactoryResolver
* already exists, retrieves the existing ComponentFactoryResolver.
*
* @returns The ComponentFactoryResolver instance to use
*/
export function injectComponentFactoryResolver(): viewEngine_ComponentFactoryResolver {
return componentFactoryResolver;
}
/**
* Represents an instance of a Component created via a {@link ComponentFactory}.
*
@ -196,7 +212,6 @@ export class ComponentFactory<T> extends viewEngine_ComponentFactory<T> {
*/
export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
destroyCbs: (() => void)[]|null = [];
location: viewEngine_ElementRef<any>;
injector: Injector;
instance: T;
hostView: ViewRef<T>;
@ -205,13 +220,12 @@ export class ComponentRef<T> extends viewEngine_ComponentRef<T> {
constructor(
componentType: Type<T>, instance: T, rootView: LViewData, injector: Injector,
hostNode: RElement) {
public location: viewEngine_ElementRef) {
super();
this.instance = instance;
this.hostView = this.changeDetectorRef = new RootViewRef<T>(rootView);
this.hostView._tViewNode = createNodeAtIndex(-1, TNodeType.View, null, null, null, rootView);
this.injector = injector;
this.location = new viewEngine_ElementRef(hostNode);
this.componentType = componentType;
}

View File

@ -9,44 +9,23 @@
// We are temporarily importing the existing viewEngine_from core so we can be sure we are
// correctly implementing its interfaces for backwards compatibility.
import {ChangeDetectorRef as viewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {getInjectableDef, getInjectorDef} from '../di/defs';
import {InjectionToken} from '../di/injection_token';
import {InjectFlags, Injector, NullInjector, inject, setCurrentInjector} from '../di/injector';
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
import {ComponentFactoryResolver as viewEngine_ComponentFactoryResolver} from '../linker/component_factory_resolver';
import {ElementRef as viewEngine_ElementRef} from '../linker/element_ref';
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
import {TemplateRef as viewEngine_TemplateRef} from '../linker/template_ref';
import {ViewContainerRef as viewEngine_ViewContainerRef} from '../linker/view_container_ref';
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
import {Renderer2} from '../render';
import {Type} from '../type';
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
import {ComponentFactoryResolver} from './component_ref';
import {getComponentDef, getDirectiveDef, getPipeDef} from './definition';
import {_getViewData, addToViewTree, assertPreviousIsParent, createEmbeddedViewAndNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentNode, getPreviousOrParentTNode, getRenderer, loadElement, renderEmbeddedTemplate, resolveDirective} from './instructions';
import {LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
import {NG_ELEMENT_ID} from './fields';
import {_getViewData, addToViewTree, assertPreviousIsParent, createEmbeddedViewAndNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentNode, getPreviousOrParentTNode, getRenderer, loadElement, renderEmbeddedTemplate, resolveDirective, setEnvironment} from './instructions';
import {DirectiveDefInternal, RenderFlags} from './interfaces/definition';
import {LInjector} from './interfaces/injector';
import {AttributeMarker, LContainerNode, LElementContainerNode, LElementNode, LNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node';
import {LQueries, QueryReadType} from './interfaces/query';
import {Renderer3, isProceduralRenderer} from './interfaces/renderer';
import {CONTEXT, DIRECTIVES, HOST_NODE, INJECTOR, LViewData, QUERIES, RENDERER, TVIEW, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getHostElementNode, getParentLNode, getParentOrContainerNode, getRenderParent, insertView, removeView} from './node_manipulation';
import {getLNode, isComponent} from './util';
import {ViewRef} from './view_ref';
/**
* If a directive is diPublic, bloomAdd sets a property on the type with this constant as
* the key and the directive's unique ID as the value. This allows us to map directives to their
* bloom filter bit for DI.
*/
const NG_ELEMENT_ID = '__NG_ELEMENT_ID__';
/**
* The number of slots in each bloom filter (used by DI). The larger this number, the fewer
@ -196,56 +175,6 @@ export function directiveInject<T>(
return getOrCreateInjectable<T>(getOrCreateNodeInjector(), token, flags);
}
/**
* Creates an ElementRef and stores it on the injector.
* Or, if the ElementRef already exists, retrieves the existing ElementRef.
*
* @returns The ElementRef instance to use
*/
export function injectElementRef(): viewEngine_ElementRef {
return createElementRef(getPreviousOrParentTNode(), _getViewData());
}
/**
* Creates a TemplateRef and stores it on the injector. Or, if the TemplateRef already
* exists, retrieves the existing TemplateRef.
*
* @returns The TemplateRef instance to use
*/
export function injectTemplateRef<T>(): viewEngine_TemplateRef<T> {
return createTemplateRef<T>(getPreviousOrParentTNode(), _getViewData());
}
/**
* Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
* already exists, retrieves the existing ViewContainerRef.
*
* @returns The ViewContainerRef instance to use
*/
export function injectViewContainerRef(): viewEngine_ViewContainerRef {
const previousTNode =
getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode;
return createContainerRef(previousTNode, _getViewData());
}
/** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */
export function injectChangeDetectorRef(): viewEngine_ChangeDetectorRef {
return createViewRef(getPreviousOrParentTNode(), _getViewData(), null);
}
/**
* Creates a ComponentFactoryResolver and stores it on the injector. Or, if the
* ComponentFactoryResolver
* already exists, retrieves the existing ComponentFactoryResolver.
*
* @returns The ComponentFactoryResolver instance to use
*/
export function injectComponentFactoryResolver(): viewEngine_ComponentFactoryResolver {
return componentFactoryResolver;
}
const componentFactoryResolver: ComponentFactoryResolver = new ComponentFactoryResolver();
export function injectRenderer2(): Renderer2 {
return getOrCreateRenderer2(getOrCreateNodeInjector());
}
@ -298,27 +227,6 @@ export function injectAttribute(attrNameToInject: string): string|undefined {
return undefined;
}
/**
* Creates a ViewRef and stores it on the injector as ChangeDetectorRef (public alias).
*
* @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
* @returns The ChangeDetectorRef to use
*/
export function createViewRef(
hostTNode: TNode, hostView: LViewData, context: any): viewEngine_ChangeDetectorRef {
if (isComponent(hostTNode)) {
const componentIndex = hostTNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
const componentView = getLNode(hostTNode, hostView).data as LViewData;
return new ViewRef(componentView, context, componentIndex);
} else if (hostTNode.type === TNodeType.Element) {
const hostComponentView = findComponentView(hostView);
return new ViewRef(hostComponentView, hostComponentView[CONTEXT], -1);
}
return null !;
}
function getOrCreateRenderer2(di: LInjector): Renderer2 {
const renderer = di.view[RENDERER];
if (isProceduralRenderer(renderer)) {
@ -342,11 +250,14 @@ function getOrCreateRenderer2(di: LInjector): Renderer2 {
export function getOrCreateInjectable<T>(
nodeInjector: LInjector, token: Type<T>| InjectionToken<T>,
flags: InjectFlags = InjectFlags.Default): T|null {
const bloomHash = bloomHashBit(token);
const bloomHash = bloomHashBitOrFactory(token);
// If the ID stored here is a function, this is a special object like ElementRef or TemplateRef
// so just call the factory function to create it.
if (typeof bloomHash === 'function') return bloomHash();
// If the token has a bloom hash, then it is a directive that is public to the injection system
// (diPublic) otherwise fall back to the module injector.
if (bloomHash !== null) {
if (bloomHash != null) {
let injector: LInjector|null = nodeInjector;
while (injector) {
@ -433,9 +344,9 @@ function searchMatchesQueuedForCreation<T>(token: any, hostTView: TView): T|null
* @param token the injection token
* @returns the matching bit to check in the bloom filter or `null` if the token is not known.
*/
function bloomHashBit(token: Type<any>| InjectionToken<any>): number|null {
let id: number|undefined = (token as any)[NG_ELEMENT_ID];
return typeof id === 'number' ? id & BLOOM_MASK : null;
function bloomHashBitOrFactory(token: Type<any>| InjectionToken<any>): number|Function|undefined {
const tokenId: number|undefined = (token as any)[NG_ELEMENT_ID] || null;
return typeof tokenId === 'number' ? tokenId & BLOOM_MASK : tokenId;
}
/**
@ -525,258 +436,18 @@ function sameHostView(injector: LInjector): boolean {
return !!injector.parent && injector.parent.view === injector.view;
}
export class ReadFromInjectorFn<T> {
constructor(readonly read: (tNode: TNode, view: LViewData, directiveIndex?: number) => T) {}
}
/**
* Creates an ElementRef for a given node injector and stores it on the injector.
*
* @param di The node injector where we should store a created ElementRef
* @returns The ElementRef instance to use
*/
export function createElementRef(tNode: TNode, view: LViewData): viewEngine_ElementRef {
return new ElementRef(getLNode(tNode, view).native);
}
export const QUERY_READ_TEMPLATE_REF = <QueryReadType<viewEngine_TemplateRef<any>>>(
new ReadFromInjectorFn<viewEngine_TemplateRef<any>>(
(tNode: TNode, view: LViewData) => { return createTemplateRef(tNode, view);}) as any);
export const QUERY_READ_CONTAINER_REF = <QueryReadType<viewEngine_ViewContainerRef>>(
new ReadFromInjectorFn<viewEngine_ViewContainerRef>(
(tNode: TNode, view: LViewData) => createContainerRef(
tNode as TElementNode | TContainerNode | TElementContainerNode, view)) as any);
export const QUERY_READ_ELEMENT_REF =
<QueryReadType<viewEngine_ElementRef>>(new ReadFromInjectorFn<viewEngine_ElementRef>(
(tNode: TNode, view: LViewData) => createElementRef(tNode, view)) as any);
export const QUERY_READ_FROM_NODE =
(new ReadFromInjectorFn<any>((tNode: TNode, view: LViewData, directiveIdx: number) => {
ngDevMode && assertNodeOfPossibleTypes(
tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
if (directiveIdx > -1) {
return view[DIRECTIVES] ![directiveIdx];
}
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) {
return createElementRef(tNode, view);
}
if (tNode.type === TNodeType.Container) {
return createTemplateRef(tNode, view);
}
if (ngDevMode) {
// should never happen
throw new Error(`Unexpected node type: ${tNode.type}`);
}
}) as any as QueryReadType<any>);
/** A ref to a node's native element. */
class ElementRef extends viewEngine_ElementRef {}
/**
* Creates a ViewContainerRef and stores it on the injector.
*
* @param hostTNode The node that is requesting a ViewContainerRef
* @param hostView The view to which the node belongs
* @returns The ViewContainerRef instance to use
*/
export function createContainerRef(
hostTNode: TElementNode | TContainerNode | TElementContainerNode,
hostView: LViewData): viewEngine_ViewContainerRef {
const hostLNode = getLNode(hostTNode, hostView);
ngDevMode && assertNodeOfPossibleTypes(
hostTNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
const lContainer = createLContainer(hostView, true);
const comment = hostView[RENDERER].createComment(ngDevMode ? 'container' : '');
const lContainerNode: LContainerNode =
createLNodeObject(TNodeType.Container, hostLNode.nodeInjector, comment, lContainer);
lContainer[RENDER_PARENT] = getRenderParent(hostTNode, hostView);
appendChild(comment, hostTNode, hostView);
if (!hostTNode.dynamicContainerNode) {
hostTNode.dynamicContainerNode =
createTNode(TNodeType.Container, -1, null, null, hostTNode, null);
}
hostLNode.dynamicLContainerNode = lContainerNode;
addToViewTree(hostView, hostTNode.index as number, lContainer);
return new ViewContainerRef(
lContainer, hostTNode.dynamicContainerNode as TContainerNode, hostTNode, hostView);
}
export class NodeInjector implements Injector {
constructor(private _lInjector: LInjector) {}
get(token: any): any {
if (token === viewEngine_TemplateRef) {
return createTemplateRef(this._lInjector.tNode, this._lInjector.view);
}
if (token === viewEngine_ViewContainerRef) {
return createContainerRef(this._lInjector.tNode, this._lInjector.view);
}
if (token === viewEngine_ElementRef) {
return createElementRef(this._lInjector.tNode, this._lInjector.view);
}
if (token === viewEngine_ChangeDetectorRef) {
return createViewRef(this._lInjector.tNode, this._lInjector.view, null);
}
if (token === Renderer2) {
return getOrCreateRenderer2(this._lInjector);
}
setEnvironment(this._lInjector.tNode, this._lInjector.view);
return getOrCreateInjectable(this._lInjector, token);
}
}
/**
* A ref to a container that enables adding and removing views from that container
* imperatively.
*/
class ViewContainerRef extends viewEngine_ViewContainerRef {
private _viewRefs: viewEngine_ViewRef[] = [];
constructor(
private _lContainer: LContainer, private _tContainerNode: TContainerNode,
private _hostTNode: TElementNode|TContainerNode|TElementContainerNode,
private _hostView: LViewData) {
super();
}
get element(): ElementRef {
// TODO: Remove LNode lookup when removing LNode.nodeInjector
const injector =
getOrCreateNodeInjectorForNode(this._getHostNode(), this._hostTNode, this._hostView);
return createElementRef(injector.tNode, injector.view);
}
get injector(): Injector {
// TODO: Remove LNode lookup when removing LNode.nodeInjector
const injector =
getOrCreateNodeInjectorForNode(this._getHostNode(), this._hostTNode, this._hostView);
return new NodeInjector(injector);
}
/** @deprecated No replacement */
get parentInjector(): Injector {
const parentLInjector = getParentLNode(this._hostTNode, this._hostView) !.nodeInjector;
return parentLInjector ? new NodeInjector(parentLInjector) : new NullInjector();
}
clear(): void {
while (this._lContainer[VIEWS].length) {
this.remove(0);
}
}
get(index: number): viewEngine_ViewRef|null { return this._viewRefs[index] || null; }
get length(): number { return this._lContainer[VIEWS].length; }
createEmbeddedView<C>(templateRef: viewEngine_TemplateRef<C>, context?: C, index?: number):
viewEngine_EmbeddedViewRef<C> {
const adjustedIdx = this._adjustIndex(index);
const viewRef = (templateRef as TemplateRef<C>)
.createEmbeddedView(
context || <any>{}, this._lContainer, this._tContainerNode,
this._hostView, adjustedIdx);
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
this._viewRefs.splice(adjustedIdx, 0, viewRef);
return viewRef;
}
createComponent<C>(
componentFactory: viewEngine_ComponentFactory<C>, index?: number|undefined,
injector?: Injector|undefined, projectableNodes?: any[][]|undefined,
ngModuleRef?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<C> {
const contextInjector = injector || this.parentInjector;
if (!ngModuleRef && contextInjector) {
ngModuleRef = contextInjector.get(viewEngine_NgModuleRef, null);
}
const componentRef =
componentFactory.create(contextInjector, projectableNodes, undefined, ngModuleRef);
this.insert(componentRef.hostView, index);
return componentRef;
}
insert(viewRef: viewEngine_ViewRef, index?: number): viewEngine_ViewRef {
if (viewRef.destroyed) {
throw new Error('Cannot insert a destroyed View in a ViewContainer!');
}
const lView = (viewRef as ViewRef<any>)._view !;
const adjustedIdx = this._adjustIndex(index);
insertView(
lView, this._lContainer, this._hostView, adjustedIdx, this._tContainerNode.parent !.index);
const container = this._getHostNode().dynamicLContainerNode !;
const beforeNode = getBeforeNodeForView(adjustedIdx, this._lContainer[VIEWS], container);
addRemoveViewFromContainer(lView, true, beforeNode);
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
this._viewRefs.splice(adjustedIdx, 0, viewRef);
return viewRef;
}
move(viewRef: viewEngine_ViewRef, newIndex: number): viewEngine_ViewRef {
const index = this.indexOf(viewRef);
this.detach(index);
this.insert(viewRef, this._adjustIndex(newIndex));
return viewRef;
}
indexOf(viewRef: viewEngine_ViewRef): number { return this._viewRefs.indexOf(viewRef); }
remove(index?: number): void {
const adjustedIdx = this._adjustIndex(index, -1);
removeView(this._lContainer, this._tContainerNode as TContainerNode, adjustedIdx);
this._viewRefs.splice(adjustedIdx, 1);
}
detach(index?: number): viewEngine_ViewRef|null {
const adjustedIdx = this._adjustIndex(index, -1);
detachView(this._lContainer, adjustedIdx, !!this._tContainerNode.detached);
return this._viewRefs.splice(adjustedIdx, 1)[0] || null;
}
private _adjustIndex(index?: number, shift: number = 0) {
if (index == null) {
return this._lContainer[VIEWS].length + shift;
}
if (ngDevMode) {
assertGreaterThan(index, -1, 'index must be positive');
// +1 because it's legal to insert at the end.
assertLessThan(index, this._lContainer[VIEWS].length + 1 + shift, 'index');
}
return index;
}
private _getHostNode() { return getLNode(this._hostTNode, this._hostView); }
}
/**
* Creates a TemplateRef and stores it on the injector.
*
* @param hostTNode The node that is requesting a TemplateRef
* @param hostView The view to which the node belongs
* @returns The TemplateRef instance to use
*/
export function createTemplateRef<T>(
hostTNode: TNode, hostView: LViewData): viewEngine_TemplateRef<T> {
const hostNode = getLNode(hostTNode, hostView);
ngDevMode && assertNodeType(hostTNode, TNodeType.Container);
ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
return new TemplateRef<any>(
hostView, createElementRef(hostTNode, hostView), hostTNode.tViews as TView, getRenderer(),
hostNode.data ![QUERIES]);
}
export function getFactoryOf<T>(type: Type<any>): ((type?: Type<T>) => T)|null {
const typeAny = type as any;
const def = getComponentDef<T>(typeAny) || getDirectiveDef<T>(typeAny) ||
@ -800,33 +471,3 @@ export function getInheritedFactory<T>(type: Type<any>): (type: Type<T>) => T {
return (t) => new t();
}
}
class TemplateRef<T> extends viewEngine_TemplateRef<T> {
constructor(
private _declarationParentView: LViewData, readonly elementRef: viewEngine_ElementRef,
private _tView: TView, private _renderer: Renderer3, private _queries: LQueries|null) {
super();
}
createEmbeddedView(
context: T, container?: LContainer, tContainerNode?: TContainerNode, hostView?: LViewData,
index?: number): viewEngine_EmbeddedViewRef<T> {
const lView = createEmbeddedViewAndNode(
this._tView, context, this._declarationParentView, this._renderer, this._queries);
if (container) {
insertView(lView, container, hostView !, index !, tContainerNode !.parent !.index);
}
renderEmbeddedTemplate(lView, this._tView, context, RenderFlags.Create);
const viewRef = new ViewRef(lView, context, -1);
viewRef._tViewNode = lView[HOST_NODE] as TViewNode;
return viewRef;
}
}
/**
* Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the
* `<ng-template>` element.
*/
export function templateRefExtractor(tNode: TContainerNode, currentView: LViewData) {
return createTemplateRef(tNode, currentView);
}

View File

@ -15,3 +15,10 @@ export const NG_INJECTOR_DEF = getClosureSafeProperty({ngInjectorDef: getClosure
export const NG_PIPE_DEF = getClosureSafeProperty({ngPipeDef: getClosureSafeProperty});
export const NG_MODULE_DEF = getClosureSafeProperty({ngModuleDef: getClosureSafeProperty});
export const NG_BASE_DEF = getClosureSafeProperty({ngBaseDef: getClosureSafeProperty});
/**
* If a directive is diPublic, bloomAdd sets a property on the type with this constant as
* the key and the directive's unique ID as the value. This allows us to map directives to their
* bloom filter bit for DI.
*/
export const NG_ELEMENT_ID = getClosureSafeProperty({__NG_ELEMENT_ID__: getClosureSafeProperty});

View File

@ -13,8 +13,8 @@ import {NgOnChangesFeature} from './features/ng_onchanges_feature';
import {PublicFeature} from './features/public_feature';
import {BaseDef, ComponentDef, ComponentDefInternal, ComponentTemplate, ComponentType, DirectiveDef, DirectiveDefFlags, DirectiveDefInternal, DirectiveType, PipeDef} from './interfaces/definition';
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, WRAP_RENDERER_FACTORY2} from './component_ref';
export {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, directiveInject, getFactoryOf, getInheritedFactory, injectAttribute, injectChangeDetectorRef, injectComponentFactoryResolver, injectElementRef, injectRenderer2, injectTemplateRef, injectViewContainerRef, templateRefExtractor} from './di';
export {ComponentFactory, ComponentFactoryResolver, ComponentRef, WRAP_RENDERER_FACTORY2, injectComponentFactoryResolver} from './component_ref';
export {directiveInject, getFactoryOf, getInheritedFactory, injectAttribute, injectRenderer2} from './di';
export {RenderFlags} from './interfaces/definition';
export {CssSelectorList} from './interfaces/projection';
@ -119,6 +119,7 @@ export {
QueryList,
query,
queryRefresh,
QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF
} from './query';
export {
registerContentQuery,
@ -138,6 +139,8 @@ export {
pureFunctionV,
} from './pure_function';
export {templateRefExtractor} from './view_engine_compatibility';
// clang-format on

View File

@ -30,7 +30,6 @@ import {isNodeMatchingSelectorList, matchingSelectorIndex} from './node_selector
import {StylingContext, allocStylingContext, createStylingContextTemplate, renderStyling as renderElementStyles, updateClassProp as updateElementClassProp, updateStyleProp as updateElementStyleProp, updateStylingMap} from './styling';
import {assertDataInRangeInternal, getLNode, isContentQueryHost, isDifferent, loadElementInternal, loadInternal, stringify} from './util';
/**
* A permanent marker promise which signifies that the current CD tree is
* clean.
@ -138,6 +137,10 @@ export function getPreviousOrParentTNode(): TNode {
return previousOrParentTNode;
}
export function setEnvironment(tNode: TNode, view: LViewData) {
previousOrParentTNode = tNode;
viewData = view;
}
/**
* If `isParent` is:

View File

@ -30,10 +30,6 @@ export const angularCoreEnv: {[name: string]: Function} = {
'ɵgetInheritedFactory': r3.getInheritedFactory,
'inject': inject,
'ɵinjectAttribute': r3.injectAttribute,
'ɵinjectChangeDetectorRef': r3.injectChangeDetectorRef,
'ɵinjectElementRef': r3.injectElementRef,
'ɵinjectTemplateRef': r3.injectTemplateRef,
'ɵinjectViewContainerRef': r3.injectViewContainerRef,
'ɵtemplateRefExtractor': r3.templateRefExtractor,
'ɵinjectRenderer2': r3.injectRenderer2,
'ɵNgOnChangesFeature': r3.NgOnChangesFeature,

View File

@ -42,14 +42,8 @@ function reflectDependency(dep: any | any[]): R3DependencyMetadata {
};
function setTokenAndResolvedType(token: any): void {
if (token === ElementRef) {
meta.resolved = R3ResolvedDependencyType.ElementRef;
} else if (token === Injector) {
if (token === Injector) {
meta.resolved = R3ResolvedDependencyType.Injector;
} else if (token === TemplateRef) {
meta.resolved = R3ResolvedDependencyType.TemplateRef;
} else if (token === ViewContainerRef) {
meta.resolved = R3ResolvedDependencyType.ViewContainerRef;
} else {
meta.resolved = R3ResolvedDependencyType.Token;
}

View File

@ -11,19 +11,23 @@
import {Observable} from 'rxjs';
import {EventEmitter} from '../event_emitter';
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
import {QueryList as viewEngine_QueryList} from '../linker/query_list';
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_container_ref';
import {Type} from '../type';
import {getSymbolIterator} from '../util';
import {assertDefined, assertEqual} from './assert';
import {ReadFromInjectorFn, getOrCreateNodeInjectorForNode} from './di';
import {_getViewData, assertPreviousIsParent, getOrCreateCurrentQueries, store, storeCleanupWithContext} from './instructions';
import {DirectiveDefInternal, unusedValueExportToPlacateAjd as unused1} from './interfaces/definition';
import {LInjector, unusedValueExportToPlacateAjd as unused2} from './interfaces/injector';
import {LContainerNode, LElementNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
import {LContainerNode, LElementNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, unusedValueExportToPlacateAjd as unused3} from './interfaces/node';
import {LQueries, QueryReadType, unusedValueExportToPlacateAjd as unused4} from './interfaces/query';
import {DIRECTIVES, LViewData, TVIEW} from './interfaces/view';
import {assertNodeOfPossibleTypes} from './node_assert';
import {flatten, getLNode, isContentQueryHost} from './util';
import {createContainerRef, createElementRef, createTemplateRef} from './view_engine_compatibility';
const unusedValueToPlacateAjd = unused1 + unused2 + unused3 + unused4;
@ -467,3 +471,63 @@ export function queryRefresh(queryList: QueryList<any>): boolean {
}
return false;
}
export class ReadFromInjectorFn<T> {
constructor(readonly read: (tNode: TNode, view: LViewData, directiveIndex?: number) => T) {}
}
// TODO: Remove wrapper function with TemplateRef when we turn on Ivy
// Necessary for now to avoid a circular dependency
export const QUERY_READ_TEMPLATE_REF =
(TemplateRefConstructor: typeof ViewEngine_TemplateRef,
ElementRefConstructor: typeof ViewEngine_ElementRef) => {
return new ReadFromInjectorFn<ViewEngine_TemplateRef<any>>(
(tNode: TNode, view: LViewData) => {
return createTemplateRef(TemplateRefConstructor, ElementRefConstructor, tNode, view);
}) as any;
};
// TODO: Remove wrapper function with ViewContainerRef when we turn on Ivy
// Necessary for now to avoid a circular dependency
export const QUERY_READ_CONTAINER_REF =
(ViewContainerRefConstructor: typeof ViewEngine_ViewContainerRef,
ElementRefConstructor: typeof ViewEngine_ElementRef) => {
return <QueryReadType<ViewEngine_ViewContainerRef>>(
new ReadFromInjectorFn<ViewEngine_ViewContainerRef>(
(tNode: TNode, view: LViewData) => createContainerRef(
ViewContainerRefConstructor, ElementRefConstructor,
tNode as TElementNode | TContainerNode | TElementContainerNode, view)) as any);
};
// TODO: Remove wrapper function with ElementRef when we turn on Ivy
// Necessary for now to avoid a circular dependency
export const QUERY_READ_ELEMENT_REF = (ElementRefConstructor: typeof ViewEngine_ElementRef) => {
return <QueryReadType<ViewEngine_ElementRef>>(
new ReadFromInjectorFn<ViewEngine_ElementRef>((tNode: TNode, view: LViewData) => {
return createElementRef(ElementRefConstructor, tNode, view);
}) as any);
};
// TODO: Remove wrapper function with TemplateRef when we turn on Ivy
export const QUERY_READ_FROM_NODE =
(TemplateRefConstructor: typeof ViewEngine_TemplateRef,
ElementRefConstructor: typeof ViewEngine_ElementRef) => {
return new ReadFromInjectorFn<any>((tNode: TNode, view: LViewData, directiveIdx: number) => {
ngDevMode && assertNodeOfPossibleTypes(
tNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
if (directiveIdx > -1) {
return view[DIRECTIVES] ![directiveIdx];
}
if (tNode.type === TNodeType.Element || tNode.type === TNodeType.ElementContainer) {
return createElementRef(ElementRefConstructor, tNode, view);
}
if (tNode.type === TNodeType.Container) {
return createTemplateRef(TemplateRefConstructor, ElementRefConstructor, tNode, view);
}
if (ngDevMode) {
// should never happen
throw new Error(`Unexpected node type: ${tNode.type}`);
}
}) as any as QueryReadType<any>;
};

View File

@ -0,0 +1,351 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef as ViewEngine_ChangeDetectorRef} from '../change_detection/change_detector_ref';
import {Injector, NullInjector} from '../di/injector';
import {ComponentFactory as viewEngine_ComponentFactory, ComponentRef as viewEngine_ComponentRef} from '../linker/component_factory';
import {ElementRef as ViewEngine_ElementRef} from '../linker/element_ref';
import {NgModuleRef as viewEngine_NgModuleRef} from '../linker/ng_module_factory';
import {TemplateRef as ViewEngine_TemplateRef} from '../linker/template_ref';
import {ViewContainerRef as ViewEngine_ViewContainerRef} from '../linker/view_container_ref';
import {EmbeddedViewRef as viewEngine_EmbeddedViewRef, ViewRef as viewEngine_ViewRef} from '../linker/view_ref';
import {assertDefined, assertGreaterThan, assertLessThan} from './assert';
import {NodeInjector, getOrCreateNodeInjectorForNode} from './di';
import {_getViewData, addToViewTree, createEmbeddedViewAndNode, createLContainer, createLNodeObject, createTNode, getPreviousOrParentTNode, getRenderer, renderEmbeddedTemplate} from './instructions';
import {LContainer, RENDER_PARENT, VIEWS} from './interfaces/container';
import {RenderFlags} from './interfaces/definition';
import {LContainerNode, TContainerNode, TElementContainerNode, TElementNode, TNode, TNodeFlags, TNodeType, TViewNode} from './interfaces/node';
import {LQueries} from './interfaces/query';
import {RComment, RElement, Renderer3} from './interfaces/renderer';
import {CONTEXT, HOST_NODE, LViewData, QUERIES, RENDERER, TView} from './interfaces/view';
import {assertNodeOfPossibleTypes, assertNodeType} from './node_assert';
import {addRemoveViewFromContainer, appendChild, detachView, findComponentView, getBeforeNodeForView, getParentLNode, getRenderParent, insertView, removeView} from './node_manipulation';
import {getLNode, isComponent} from './util';
import {ViewRef} from './view_ref';
/**
* Creates an ElementRef from the most recent node.
*
* @returns The ElementRef instance to use
*/
export function injectElementRef(ElementRefToken: typeof ViewEngine_ElementRef):
ViewEngine_ElementRef {
return createElementRef(ElementRefToken, getPreviousOrParentTNode(), _getViewData());
}
let R3ElementRef: {new (native: RElement | RComment): ViewEngine_ElementRef};
/**
* Creates an ElementRef given a node.
*
* @param ElementRefToken The ElementRef type
* @param tNode The node for which you'd like an ElementRef
* @param view The view to which the node belongs
* @returns The ElementRef instance to use
*/
export function createElementRef(
ElementRefToken: typeof ViewEngine_ElementRef, tNode: TNode,
view: LViewData): ViewEngine_ElementRef {
if (!R3ElementRef) {
// TODO: Fix class name, should be ElementRef, but there appears to be a rollup bug
R3ElementRef = class ElementRef_ extends ElementRefToken {};
}
return new R3ElementRef(getLNode(tNode, view).native);
}
let R3TemplateRef: {
new (
_declarationParentView: LViewData, elementRef: ViewEngine_ElementRef, _tView: TView,
_renderer: Renderer3, _queries: LQueries | null): ViewEngine_TemplateRef<any>
};
/**
* Creates a TemplateRef given a node.
*
* @returns The TemplateRef instance to use
*/
export function injectTemplateRef<T>(
TemplateRefToken: typeof ViewEngine_TemplateRef,
ElementRefToken: typeof ViewEngine_ElementRef): ViewEngine_TemplateRef<T> {
return createTemplateRef<T>(
TemplateRefToken, ElementRefToken, getPreviousOrParentTNode(), _getViewData());
}
/**
* Creates a TemplateRef and stores it on the injector.
*
* @param TemplateRefToken The TemplateRef type
* @param ElementRefToken The ElementRef type
* @param hostTNode The node that is requesting a TemplateRef
* @param hostView The view to which the node belongs
* @returns The TemplateRef instance to use
*/
export function createTemplateRef<T>(
TemplateRefToken: typeof ViewEngine_TemplateRef, ElementRefToken: typeof ViewEngine_ElementRef,
hostTNode: TNode, hostView: LViewData): ViewEngine_TemplateRef<T> {
if (!R3TemplateRef) {
// TODO: Fix class name, should be TemplateRef, but there appears to be a rollup bug
R3TemplateRef = class TemplateRef_<T> extends TemplateRefToken<T> {
constructor(
private _declarationParentView: LViewData, readonly elementRef: ViewEngine_ElementRef,
private _tView: TView, private _renderer: Renderer3, private _queries: LQueries|null) {
super();
}
createEmbeddedView(
context: T, container?: LContainer, tContainerNode?: TContainerNode, hostView?: LViewData,
index?: number): viewEngine_EmbeddedViewRef<T> {
const lView = createEmbeddedViewAndNode(
this._tView, context, this._declarationParentView, this._renderer, this._queries);
if (container) {
insertView(lView, container, hostView !, index !, tContainerNode !.parent !.index);
}
renderEmbeddedTemplate(lView, this._tView, context, RenderFlags.Create);
const viewRef = new ViewRef(lView, context, -1);
viewRef._tViewNode = lView[HOST_NODE] as TViewNode;
return viewRef;
}
};
}
const hostNode = getLNode(hostTNode, hostView);
ngDevMode && assertNodeType(hostTNode, TNodeType.Container);
ngDevMode && assertDefined(hostTNode.tViews, 'TView must be allocated');
return new R3TemplateRef(
hostView, createElementRef(ElementRefToken, hostTNode, hostView), hostTNode.tViews as TView,
getRenderer(), hostNode.data ![QUERIES]);
}
/**
* Retrieves `TemplateRef` instance from `Injector` when a local reference is placed on the
* `<ng-template>` element.
*/
export function templateRefExtractor(
TemplateRefToken: typeof ViewEngine_TemplateRef,
ElementRefToken: typeof ViewEngine_ElementRef) {
return (tNode: TNode, currentView: LViewData) => {
return createTemplateRef(TemplateRefToken, ElementRefToken, tNode, currentView);
};
}
let R3ViewContainerRef: {
new (
lContainer: LContainer, tContainerNode: TContainerNode,
hostTNode: TElementNode | TContainerNode | TElementContainerNode, hostView: LViewData):
ViewEngine_ViewContainerRef
};
/**
* Creates a ViewContainerRef and stores it on the injector. Or, if the ViewContainerRef
* already exists, retrieves the existing ViewContainerRef.
*
* @returns The ViewContainerRef instance to use
*/
export function injectViewContainerRef(
ViewContainerRefToken: typeof ViewEngine_ViewContainerRef,
ElementRefToken: typeof ViewEngine_ElementRef): ViewEngine_ViewContainerRef {
const previousTNode =
getPreviousOrParentTNode() as TElementNode | TElementContainerNode | TContainerNode;
return createContainerRef(ViewContainerRefToken, ElementRefToken, previousTNode, _getViewData());
}
/**
* Creates a ViewContainerRef and stores it on the injector.
*
* @param ViewContainerRefToken The ViewContainerRef type
* @param ElementRefToken The ElementRef type
* @param hostTNode The node that is requesting a ViewContainerRef
* @param hostView The view to which the node belongs
* @returns The ViewContainerRef instance to use
*/
export function createContainerRef(
ViewContainerRefToken: typeof ViewEngine_ViewContainerRef,
ElementRefToken: typeof ViewEngine_ElementRef,
hostTNode: TElementNode|TContainerNode|TElementContainerNode,
hostView: LViewData): ViewEngine_ViewContainerRef {
if (!R3ViewContainerRef) {
// TODO: Fix class name, should be ViewContainerRef, but there appears to be a rollup bug
R3ViewContainerRef = class ViewContainerRef_ extends ViewContainerRefToken {
private _viewRefs: viewEngine_ViewRef[] = [];
constructor(
private _lContainer: LContainer, private _tContainerNode: TContainerNode,
private _hostTNode: TElementNode|TContainerNode|TElementContainerNode,
private _hostView: LViewData) {
super();
}
get element(): ViewEngine_ElementRef {
return createElementRef(ElementRefToken, this._hostTNode, this._hostView);
}
get injector(): Injector {
// TODO: Remove LNode lookup when removing LNode.nodeInjector
const injector =
getOrCreateNodeInjectorForNode(this._getHostNode(), this._hostTNode, this._hostView);
return new NodeInjector(injector);
}
/** @deprecated No replacement */
get parentInjector(): Injector {
const parentLInjector = getParentLNode(this._hostTNode, this._hostView) !.nodeInjector;
return parentLInjector ? new NodeInjector(parentLInjector) : new NullInjector();
}
clear(): void {
while (this._lContainer[VIEWS].length) {
this.remove(0);
}
}
get(index: number): viewEngine_ViewRef|null { return this._viewRefs[index] || null; }
get length(): number { return this._lContainer[VIEWS].length; }
createEmbeddedView<C>(templateRef: ViewEngine_TemplateRef<C>, context?: C, index?: number):
viewEngine_EmbeddedViewRef<C> {
const adjustedIdx = this._adjustIndex(index);
const viewRef = (templateRef as any)
.createEmbeddedView(
context || <any>{}, this._lContainer, this._tContainerNode,
this._hostView, adjustedIdx);
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
this._viewRefs.splice(adjustedIdx, 0, viewRef);
return viewRef;
}
createComponent<C>(
componentFactory: viewEngine_ComponentFactory<C>, index?: number|undefined,
injector?: Injector|undefined, projectableNodes?: any[][]|undefined,
ngModuleRef?: viewEngine_NgModuleRef<any>|undefined): viewEngine_ComponentRef<C> {
const contextInjector = injector || this.parentInjector;
if (!ngModuleRef && contextInjector) {
ngModuleRef = contextInjector.get(viewEngine_NgModuleRef, null);
}
const componentRef =
componentFactory.create(contextInjector, projectableNodes, undefined, ngModuleRef);
this.insert(componentRef.hostView, index);
return componentRef;
}
insert(viewRef: viewEngine_ViewRef, index?: number): viewEngine_ViewRef {
if (viewRef.destroyed) {
throw new Error('Cannot insert a destroyed View in a ViewContainer!');
}
const lView = (viewRef as ViewRef<any>)._view !;
const adjustedIdx = this._adjustIndex(index);
insertView(
lView, this._lContainer, this._hostView, adjustedIdx,
this._tContainerNode.parent !.index);
const container = this._getHostNode().dynamicLContainerNode !;
const beforeNode = getBeforeNodeForView(adjustedIdx, this._lContainer[VIEWS], container);
addRemoveViewFromContainer(lView, true, beforeNode);
(viewRef as ViewRef<any>).attachToViewContainerRef(this);
this._viewRefs.splice(adjustedIdx, 0, viewRef);
return viewRef;
}
move(viewRef: viewEngine_ViewRef, newIndex: number): viewEngine_ViewRef {
const index = this.indexOf(viewRef);
this.detach(index);
this.insert(viewRef, this._adjustIndex(newIndex));
return viewRef;
}
indexOf(viewRef: viewEngine_ViewRef): number { return this._viewRefs.indexOf(viewRef); }
remove(index?: number): void {
const adjustedIdx = this._adjustIndex(index, -1);
removeView(this._lContainer, this._tContainerNode as TContainerNode, adjustedIdx);
this._viewRefs.splice(adjustedIdx, 1);
}
detach(index?: number): viewEngine_ViewRef|null {
const adjustedIdx = this._adjustIndex(index, -1);
detachView(this._lContainer, adjustedIdx, !!this._tContainerNode.detached);
return this._viewRefs.splice(adjustedIdx, 1)[0] || null;
}
private _adjustIndex(index?: number, shift: number = 0) {
if (index == null) {
return this._lContainer[VIEWS].length + shift;
}
if (ngDevMode) {
assertGreaterThan(index, -1, 'index must be positive');
// +1 because it's legal to insert at the end.
assertLessThan(index, this._lContainer[VIEWS].length + 1 + shift, 'index');
}
return index;
}
private _getHostNode() { return getLNode(this._hostTNode, this._hostView); }
};
}
const hostLNode = getLNode(hostTNode, hostView);
ngDevMode && assertNodeOfPossibleTypes(
hostTNode, TNodeType.Container, TNodeType.Element, TNodeType.ElementContainer);
const lContainer = createLContainer(hostView, true);
const comment = hostView[RENDERER].createComment(ngDevMode ? 'container' : '');
const lContainerNode: LContainerNode =
createLNodeObject(TNodeType.Container, hostLNode.nodeInjector, comment, lContainer);
lContainer[RENDER_PARENT] = getRenderParent(hostTNode, hostView);
appendChild(comment, hostTNode, hostView);
if (!hostTNode.dynamicContainerNode) {
hostTNode.dynamicContainerNode =
createTNode(TNodeType.Container, -1, null, null, hostTNode, null);
}
hostLNode.dynamicLContainerNode = lContainerNode;
addToViewTree(hostView, hostTNode.index as number, lContainer);
return new R3ViewContainerRef(
lContainer, hostTNode.dynamicContainerNode as TContainerNode, hostTNode, hostView);
}
/** Returns a ChangeDetectorRef (a.k.a. a ViewRef) */
export function injectChangeDetectorRef(): ViewEngine_ChangeDetectorRef {
return createViewRef(getPreviousOrParentTNode(), _getViewData(), null);
}
/**
* Creates a ViewRef and stores it on the injector as ChangeDetectorRef (public alias).
*
* @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
* @returns The ChangeDetectorRef to use
*/
export function createViewRef(
hostTNode: TNode, hostView: LViewData, context: any): ViewEngine_ChangeDetectorRef {
if (isComponent(hostTNode)) {
const componentIndex = hostTNode.flags >> TNodeFlags.DirectiveStartingIndexShift;
const componentView = getLNode(hostTNode, hostView).data as LViewData;
return new ViewRef(componentView, context, componentIndex);
} else if (hostTNode.type === TNodeType.Element) {
const hostComponentView = findComponentView(hostView);
return new ViewRef(hostComponentView, hostComponentView[CONTEXT], -1);
}
return null !;
}

View File

@ -32,9 +32,6 @@
{
"name": "ChangeDetectionStrategy"
},
{
"name": "ChangeDetectorRef"
},
{
"name": "CorePlayerHandler"
},
@ -65,9 +62,6 @@
{
"name": "ElementRef"
},
{
"name": "ElementRef$1"
},
{
"name": "FLAGS"
},
@ -146,6 +140,15 @@
{
"name": "QUERIES"
},
{
"name": "R3_ELEMENT_REF_FACTORY"
},
{
"name": "R3_TEMPLATE_REF_FACTORY"
},
{
"name": "R3_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "RENDERER"
},
@ -179,18 +182,12 @@
{
"name": "TemplateRef"
},
{
"name": "TemplateRef$1"
},
{
"name": "VIEWS"
},
{
"name": "ViewContainerRef"
},
{
"name": "ViewContainerRef$1"
},
{
"name": "ViewEncapsulation$1"
},
@ -300,7 +297,7 @@
"name": "bloomFindPossibleInjector"
},
{
"name": "bloomHashBit"
"name": "bloomHashBitOrFactory"
},
{
"name": "buildAnimationPlayer"
@ -401,9 +398,6 @@
{
"name": "createViewQuery"
},
{
"name": "createViewRef"
},
{
"name": "defineComponent"
},
@ -719,9 +713,6 @@
{
"name": "isClassBased"
},
{
"name": "isComponent"
},
{
"name": "isComponentInstance"
},
@ -926,6 +917,9 @@
{
"name": "setDirty"
},
{
"name": "setEnvironment"
},
{
"name": "setFlag"
},

View File

@ -1238,9 +1238,21 @@
{
"name": "Quote"
},
{
"name": "R3_CHANGE_DETECTOR_REF_FACTORY$1"
},
{
"name": "R3_COMPILE_INJECTABLE$1"
},
{
"name": "R3_ELEMENT_REF_FACTORY$1"
},
{
"name": "R3_TEMPLATE_REF_FACTORY$1"
},
{
"name": "R3_VIEW_CONTAINER_REF_FACTORY$1"
},
{
"name": "ReadKeyExpr"
},
@ -3389,6 +3401,9 @@
{
"name": "noop$3"
},
{
"name": "noopFactory"
},
{
"name": "noopScope"
},

View File

@ -26,9 +26,6 @@
{
"name": "ChangeDetectionStrategy"
},
{
"name": "ChangeDetectorRef"
},
{
"name": "DECLARATION_VIEW"
},
@ -50,9 +47,6 @@
{
"name": "ElementRef"
},
{
"name": "ElementRef$1"
},
{
"name": "FLAGS"
},
@ -137,6 +131,15 @@
{
"name": "QUERIES"
},
{
"name": "R3_ELEMENT_REF_FACTORY"
},
{
"name": "R3_TEMPLATE_REF_FACTORY"
},
{
"name": "R3_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "RENDERER"
},
@ -167,9 +170,6 @@
{
"name": "TemplateRef"
},
{
"name": "TemplateRef$1"
},
{
"name": "ToDoAppComponent_footer_Template_6"
},
@ -200,9 +200,6 @@
{
"name": "ViewContainerRef"
},
{
"name": "ViewContainerRef$1"
},
{
"name": "ViewEncapsulation$1"
},
@ -366,7 +363,7 @@
"name": "bloomFindPossibleInjector"
},
{
"name": "bloomHashBit"
"name": "bloomHashBitOrFactory"
},
{
"name": "cacheMatchingDirectivesForNode"
@ -464,9 +461,6 @@
{
"name": "createViewQuery"
},
{
"name": "createViewRef"
},
{
"name": "defineComponent"
},
@ -722,6 +716,9 @@
{
"name": "inject"
},
{
"name": "injectElementRef"
},
{
"name": "injectTemplateRef"
},
@ -740,9 +737,6 @@
{
"name": "invertObject"
},
{
"name": "isComponent"
},
{
"name": "isContentQueryHost"
},
@ -944,6 +938,9 @@
{
"name": "setDirty"
},
{
"name": "setEnvironment"
},
{
"name": "setFlag"
},

View File

@ -281,9 +281,6 @@
{
"name": "ElementRef"
},
{
"name": "ElementRef$1"
},
{
"name": "EmulatedEncapsulationDomRenderer2"
},
@ -662,6 +659,18 @@
{
"name": "R3Injector"
},
{
"name": "R3_CHANGE_DETECTOR_REF_FACTORY"
},
{
"name": "R3_ELEMENT_REF_FACTORY"
},
{
"name": "R3_TEMPLATE_REF_FACTORY"
},
{
"name": "R3_VIEW_CONTAINER_REF_FACTORY"
},
{
"name": "REMOVE_EVENT_LISTENER"
},
@ -809,9 +818,6 @@
{
"name": "TemplateRef"
},
{
"name": "TemplateRef$1"
},
{
"name": "Testability"
},
@ -890,9 +896,6 @@
{
"name": "ViewContainerRef"
},
{
"name": "ViewContainerRef$1"
},
{
"name": "ViewEncapsulation$1"
},
@ -1200,7 +1203,7 @@
"name": "bloomFindPossibleInjector"
},
{
"name": "bloomHashBit"
"name": "bloomHashBitOrFactory"
},
{
"name": "cacheMatchingDirectivesForNode"
@ -2288,6 +2291,9 @@
{
"name": "setDirty"
},
{
"name": "setEnvironment"
},
{
"name": "setFlag"
},

View File

@ -5,7 +5,9 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {ElementRef, TemplateRef} from '@angular/core';
import {RenderFlags} from '@angular/core/src/render3';
import {AnimationContext, PlayState, Player, PlayerHandler} from '../../../src/render3/animations/interfaces';
import {addPlayer, getOrCreateAnimationContext, getPlayers} from '../../../src/render3/animations/players';
import {QUERY_READ_FROM_NODE, defineComponent, getHostElement} from '../../../src/render3/index';
@ -13,6 +15,7 @@ import {element, elementEnd, elementStart, elementStyling, elementStylingApply,
import {RElement} from '../../../src/render3/interfaces/renderer';
import {QueryList, query, queryRefresh} from '../../../src/render3/query';
import {ComponentFixture} from '../render_util';
import {MockPlayer} from './mock_player';
describe('animation player access', () => {
@ -286,7 +289,7 @@ class SuperComp {
},
viewQuery: function(rf: RenderFlags, ctx: SuperComp) {
if (rf & RenderFlags.Create) {
query(0, ['child'], true, QUERY_READ_FROM_NODE);
query(0, ['child'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;

View File

@ -10,7 +10,8 @@ import {withBody} from '@angular/private/testing';
import {ChangeDetectionStrategy, ChangeDetectorRef, DoCheck, RendererType2} from '../../src/core';
import {getRenderedText, whenRendered} from '../../src/render3/component';
import {LifecycleHooksFeature, defineComponent, defineDirective, injectChangeDetectorRef} from '../../src/render3/index';
import {directiveInject} from '../../src/render3/di';
import {LifecycleHooksFeature, defineComponent, defineDirective} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, detectChanges, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, listener, markDirty, text, textBinding, tick} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {RElement, Renderer3, RendererFactory3} from '../../src/render3/interfaces/renderer';
@ -18,7 +19,6 @@ import {RElement, Renderer3, RendererFactory3} from '../../src/render3/interface
import {containerEl, createComponent, renderComponent, requestAnimationFrame} from './render_util';
describe('change detection', () => {
describe('markDirty, detectChanges, whenRendered, getRenderedText', () => {
class MyComponent implements DoCheck {
value: string = 'works';
@ -326,7 +326,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: () => myComp = new MyComp(injectChangeDetectorRef()),
factory: () => myComp = new MyComp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 1,
/** {{ name }} */
@ -352,7 +352,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: ParentComp,
selectors: [['parent-comp']],
factory: () => new ParentComp(injectChangeDetectorRef()),
factory: () => new ParentComp(directiveInject(ChangeDetectorRef as any)),
consts: 2,
vars: 1,
/**
@ -378,7 +378,7 @@ describe('change detection', () => {
static ngDirectiveDef = defineDirective({
type: Dir,
selectors: [['', 'dir', '']],
factory: () => dir = new Dir(injectChangeDetectorRef())
factory: () => dir = new Dir(directiveInject(ChangeDetectorRef as any))
});
}
@ -487,7 +487,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()),
factory: () => new MyApp(directiveInject(ChangeDetectorRef as any)),
consts: 2,
vars: 1,
/**
@ -542,7 +542,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: DetectChangesComp,
selectors: [['detect-changes-comp']],
factory: () => new DetectChangesComp(injectChangeDetectorRef()),
factory: () => new DetectChangesComp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 1,
/** {{ value }} */
@ -575,7 +575,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: DetectChangesComp,
selectors: [['detect-changes-comp']],
factory: () => new DetectChangesComp(injectChangeDetectorRef()),
factory: () => new DetectChangesComp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 1,
/** {{ doCheckCount }} */
@ -605,7 +605,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()),
factory: () => new MyApp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 0,
/** <detached-comp></detached-comp> */
@ -629,7 +629,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: DetachedComp,
selectors: [['detached-comp']],
factory: () => comp = new DetachedComp(injectChangeDetectorRef()),
factory: () => comp = new DetachedComp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 1,
/** {{ value }} */
@ -730,7 +730,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: OnPushComp,
selectors: [['on-push-comp']],
factory: () => onPushComp = new OnPushComp(injectChangeDetectorRef()),
factory: () => onPushComp = new OnPushComp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 1,
/** {{ value }} */
@ -791,7 +791,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: OnPushComp,
selectors: [['on-push-comp']],
factory: () => comp = new OnPushComp(injectChangeDetectorRef()),
factory: () => comp = new OnPushComp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 1,
/** {{ value }} */
@ -960,7 +960,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: NoChangesComp,
selectors: [['no-changes-comp']],
factory: () => comp = new NoChangesComp(injectChangeDetectorRef()),
factory: () => comp = new NoChangesComp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 1,
template: (rf: RenderFlags, ctx: NoChangesComp) => {
@ -982,7 +982,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: AppComp,
selectors: [['app-comp']],
factory: () => new AppComp(injectChangeDetectorRef()),
factory: () => new AppComp(directiveInject(ChangeDetectorRef as any)),
consts: 2,
vars: 1,
/**
@ -1045,7 +1045,7 @@ describe('change detection', () => {
static ngComponentDef = defineComponent({
type: EmbeddedViewApp,
selectors: [['embedded-view-app']],
factory: () => new EmbeddedViewApp(injectChangeDetectorRef()),
factory: () => new EmbeddedViewApp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 0,
/**

View File

@ -7,6 +7,7 @@
*/
import {NgForOfContext} from '@angular/common';
import {ElementRef, TemplateRef} from '@angular/core';
import {AttributeMarker, defineComponent, templateRefExtractor} from '../../src/render3/index';
import {bind, template, elementEnd, elementProperty, elementStart, getCurrentView, interpolation1, interpolation2, interpolation3, interpolationV, listener, load, nextContext, restoreView, text, textBinding, elementContainerStart, elementContainerEnd, reference} from '../../src/render3/instructions';
@ -896,11 +897,15 @@ describe('@angular/common integration', () => {
*/
template: (rf: RenderFlags, myApp: MyApp) => {
if (rf & RenderFlags.Create) {
template(0, (rf1: RenderFlags) => {
if (rf1 & RenderFlags.Create) {
text(0, 'from tpl');
}
}, 1, 0, undefined, undefined, ['tpl', ''], templateRefExtractor);
template(
0,
(rf1: RenderFlags) => {
if (rf1 & RenderFlags.Create) {
text(0, 'from tpl');
}
},
1, 0, undefined, undefined, ['tpl', ''],
templateRefExtractor(TemplateRef, ElementRef));
template(2, null, 0, 0, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
}
if (rf & RenderFlags.Update) {
@ -939,11 +944,15 @@ describe('@angular/common integration', () => {
*/
template: (rf: RenderFlags, myApp: MyApp) => {
if (rf & RenderFlags.Create) {
template(0, (rf1: RenderFlags) => {
if (rf1 & RenderFlags.Create) {
text(0, 'from tpl');
}
}, 1, 0, undefined, undefined, ['tpl', ''], templateRefExtractor);
template(
0,
(rf1: RenderFlags) => {
if (rf1 & RenderFlags.Create) {
text(0, 'from tpl');
}
},
1, 0, undefined, undefined, ['tpl', ''],
templateRefExtractor(TemplateRef, ElementRef));
elementContainerStart(2, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
elementContainerEnd();
}

View File

@ -7,9 +7,9 @@
*/
import {NgForOf as NgForOfDef, NgIf as NgIfDef, NgTemplateOutlet as NgTemplateOutletDef} from '@angular/common';
import {IterableDiffers} from '@angular/core';
import {IterableDiffers, TemplateRef, ViewContainerRef} from '@angular/core';
import {DirectiveType, NgOnChangesFeature, defineDirective, directiveInject, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {DirectiveType, NgOnChangesFeature, defineDirective, directiveInject} from '../../src/render3/index';
export const NgForOf: DirectiveType<NgForOfDef<any>> = NgForOfDef as any;
export const NgIf: DirectiveType<NgIfDef> = NgIfDef as any;
@ -19,7 +19,8 @@ NgForOf.ngDirectiveDef = defineDirective({
type: NgForOfDef,
selectors: [['', 'ngForOf', '']],
factory: () => new NgForOfDef(
injectViewContainerRef(), injectTemplateRef(), directiveInject(IterableDiffers)),
directiveInject(ViewContainerRef as any), directiveInject(TemplateRef as any),
directiveInject(IterableDiffers)),
inputs: {
ngForOf: 'ngForOf',
ngForTrackBy: 'ngForTrackBy',
@ -30,14 +31,15 @@ NgForOf.ngDirectiveDef = defineDirective({
(NgIf as any).ngDirectiveDef = defineDirective({
type: NgIfDef,
selectors: [['', 'ngIf', '']],
factory: () => new NgIfDef(injectViewContainerRef(), injectTemplateRef()),
factory: () => new NgIfDef(
directiveInject(ViewContainerRef as any), directiveInject(TemplateRef as any)),
inputs: {ngIf: 'ngIf', ngIfThen: 'ngIfThen', ngIfElse: 'ngIfElse'}
});
(NgTemplateOutlet as any).ngDirectiveDef = defineDirective({
type: NgTemplateOutletDef,
selectors: [['', 'ngTemplateOutlet', '']],
factory: () => new NgTemplateOutletDef(injectViewContainerRef()),
factory: () => new NgTemplateOutletDef(directiveInject(ViewContainerRef as any)),
features: [NgOnChangesFeature],
inputs:
{ngTemplateOutlet: 'ngTemplateOutlet', ngTemplateOutletContext: 'ngTemplateOutletContext'}

View File

@ -394,7 +394,7 @@ describe('components & directives', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: IfDirective,
selectors: [['', 'if', '']],
factory: () => new IfDirective($r3$.ɵinjectTemplateRef()),
factory: () => new IfDirective($r3$.ɵdirectiveInject(TemplateRef as any)),
});
// /NORMATIVE
}

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {Attribute, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, INJECTOR, Inject, InjectFlags, Injectable, Injector, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, SkipSelf, TemplateRef, ViewChild, ViewChildren, ViewContainerRef, defineInjectable, defineInjector, inject} from '../../../src/core';
import {Attribute, ChangeDetectorRef, Component, INJECTOR, Inject, InjectFlags, Injectable, Injector, SkipSelf, defineInjectable, inject} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {renderComponent, toHtml} from '../render_util';
@ -32,7 +32,7 @@ describe('injection', () => {
type: MyComp,
selectors: [['my-comp']],
factory: function MyComp_Factory() {
return new MyComp($r3$.ɵinjectChangeDetectorRef());
return new MyComp($r3$.ɵdirectiveInject(ChangeDetectorRef as any));
},
consts: 1,
vars: 1,

View File

@ -6,10 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ElementRef, TemplateRef} from '@angular/core';
import {Component} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentFixture} from '../render_util';
/// See: `normative.md`
describe('local references', () => {
type $RenderFlags$ = $r3$.ɵRenderFlags;
@ -69,7 +72,7 @@ describe('local references', () => {
if (rf & 1) {
$r3$.ɵtemplate(
0, MyComponent_Template_0, 0, 0, null, null, ['tpl', ''],
$r3$.ɵtemplateRefExtractor);
$r3$.ɵtemplateRefExtractor(TemplateRef, ElementRef));
$r3$.ɵtext(2);
}
if (rf & 2) {

View File

@ -6,12 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import {Component, Directive, Input, OnDestroy, Pipe, PipeTransform, TemplateRef, ViewContainerRef} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentDefInternal} from '../../../src/render3/interfaces/definition';
import {containerEl, renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('pipes', () => {
type $any$ = any;
@ -145,7 +146,9 @@ describe('pipes', () => {
static ngDirectiveDef = $r3$.ɵdefineDirective({
type: OneTimeIf,
selectors: [['', 'oneTimeIf', '']],
factory: () => new OneTimeIf($r3$.ɵinjectViewContainerRef(), $r3$.ɵinjectTemplateRef()),
factory: () => new OneTimeIf(
$r3$.ɵdirectiveInject(ViewContainerRef as any),
$r3$.ɵdirectiveInject(TemplateRef as any)),
inputs: {oneTimeIf: 'oneTimeIf'}
});
// /NORMATIVE

View File

@ -6,12 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, Directive, HostBinding, HostListener, Injectable, Input, NgModule, OnDestroy, Optional, Pipe, PipeTransform, QueryList, SimpleChanges, TemplateRef, ViewChild, ViewChildren, ViewContainerRef} from '../../../src/core';
import {Component, Directive, Input, SimpleChanges, TemplateRef, ViewContainerRef, inject} from '../../../src/core';
import * as $r3$ from '../../../src/core_render3_private_export';
import {ComponentDefInternal} from '../../../src/render3/interfaces/definition';
import {renderComponent, toHtml} from '../render_util';
/// See: `normative.md`
describe('template variables', () => {
type $any$ = any;
@ -69,7 +70,9 @@ describe('template variables', () => {
type: ForOfDirective,
selectors: [['', 'forOf', '']],
factory: function ForOfDirective_Factory() {
return new ForOfDirective($r3$.ɵinjectViewContainerRef(), $r3$.ɵinjectTemplateRef());
return new ForOfDirective(
$r3$.ɵdirectiveInject(ViewContainerRef as any),
$r3$.ɵdirectiveInject(TemplateRef as any));
},
// TODO(chuckj): Enable when ngForOf enabling lands.
// features: [NgOnChangesFeature],

View File

@ -8,9 +8,6 @@
import {SelectorFlags} from '@angular/core/src/render3/interfaces/projection';
import {Input, TemplateRef, ViewContainerRef, ViewRef} from '../../src/core';
import {defineDirective} from '../../src/render3/definition';
import {injectTemplateRef, injectViewContainerRef} from '../../src/render3/di';
import {AttributeMarker, detectChanges} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, loadDirective, projection, projectionDef, template, text} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';

View File

@ -11,7 +11,8 @@ import {RenderFlags} from '@angular/core/src/render3/interfaces/definition';
import {defineComponent} from '../../src/render3/definition';
import {bloomAdd, bloomFindPossibleInjector, getOrCreateNodeInjector, injectAttribute} from '../../src/render3/di';
import {PublicFeature, defineDirective, directiveInject, injectChangeDetectorRef, injectElementRef, injectRenderer2, injectTemplateRef, injectViewContainerRef, load} from '../../src/render3/index';
import {PublicFeature, defineDirective, directiveInject, injectRenderer2, load} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, createNodeAtIndex, createLViewData, createTView, element, elementEnd, elementStart, embeddedViewEnd, embeddedViewStart, enterView, interpolation2, leaveView, projection, projectionDef, reference, template, text, textBinding, loadDirective, elementContainerStart, elementContainerEnd} from '../../src/render3/instructions';
import {LInjector} from '../../src/render3/interfaces/injector';
import {isProceduralRenderer} from '../../src/render3/interfaces/renderer';
@ -786,445 +787,456 @@ describe('di', () => {
});
describe('ElementRef', () => {
it('should create directive with ElementRef dependencies', () => {
let dir !: Directive;
let dirSameInstance !: DirectiveSameInstance;
let divNode !: LElementNode;
describe('Special tokens', () => {
describe('ElementRef', () => {
it('should create directive with ElementRef dependencies', () => {
let dir !: Directive;
let dirSameInstance !: DirectiveSameInstance;
let divNode !: LElementNode;
class Directive {
value: string;
constructor(public elementRef: ElementRef) {
this.value = (elementRef.constructor as any).name;
}
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => dir = new Directive(directiveInject(ElementRef)),
features: [PublicFeature],
exportAs: 'dir'
});
}
class DirectiveSameInstance {
isSameInstance: boolean;
constructor(public elementRef: ElementRef, directive: Directive) {
this.isSameInstance = elementRef === directive.elementRef;
}
static ngDirectiveDef = defineDirective({
type: DirectiveSameInstance,
selectors: [['', 'dirSame', '']],
factory: () => dirSameInstance = new DirectiveSameInstance(
directiveInject(ElementRef), directiveInject(Directive)),
exportAs: 'dirSame'
});
}
/** <div dir dirSame></div> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', '']);
elementEnd();
divNode = load(0);
}
}, 1, 0, [Directive, DirectiveSameInstance]);
const fixture = new ComponentFixture(App);
expect(dir.value).toContain('ElementRef');
expect(dir.elementRef.nativeElement).toEqual(divNode.native);
expect(dirSameInstance.elementRef.nativeElement).toEqual(divNode.native);
// Each ElementRef instance should be unique
expect(dirSameInstance.isSameInstance).toBe(false);
});
it('should create ElementRef with comment if requesting directive is on <ng-template> node',
() => {
let dir !: Directive;
let commentNode !: LContainerNode;
class Directive {
value: string;
constructor(public elementRef: ElementRef) {
this.value = (elementRef.constructor as any).name;
}
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => dir = new Directive(directiveInject(ElementRef)),
features: [PublicFeature],
exportAs: 'dir'
});
}
/** <ng-template dir></ng-template> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, () => {}, 0, 0, null, ['dir', '']);
commentNode = load(0);
}
}, 1, 0, [Directive]);
const fixture = new ComponentFixture(App);
expect(dir.value).toContain('ElementRef');
expect(dir.elementRef.nativeElement).toEqual(commentNode.native);
});
});
describe('TemplateRef', () => {
it('should create directive with TemplateRef dependencies', () => {
class Directive {
value: string;
constructor(public templateRef: TemplateRef<any>) {
this.value = (templateRef.constructor as any).name;
}
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => new Directive(directiveInject(TemplateRef as any)),
features: [PublicFeature],
exportAs: 'dir'
});
}
class DirectiveSameInstance {
isSameInstance: boolean;
constructor(templateRef: TemplateRef<any>, directive: Directive) {
this.isSameInstance = templateRef === directive.templateRef;
}
static ngDirectiveDef = defineDirective({
type: DirectiveSameInstance,
selectors: [['', 'dirSame', '']],
factory: () => new DirectiveSameInstance(
directiveInject(TemplateRef as any), directiveInject(Directive)),
exportAs: 'dirSame'
});
}
/**
* <ng-template dir dirSame #dir="dir" #dirSame="dirSame">
* {{ dir.value }} - {{ dirSame.value }}
* </ng-template>
*/
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, function() {
}, 0, 0, undefined, ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
text(3);
}
if (rf & RenderFlags.Update) {
const tmp1 = reference(1) as any;
const tmp2 = reference(2) as any;
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.isSameInstance, ''));
}
}, 4, 2, [Directive, DirectiveSameInstance]);
const fixture = new ComponentFixture(App);
// Each TemplateRef instance should be unique
expect(fixture.html).toContain('TemplateRef');
expect(fixture.html).toContain('false');
});
});
describe('ViewContainerRef', () => {
it('should create directive with ViewContainerRef dependencies', () => {
class Directive {
value: string;
constructor(public viewContainerRef: ViewContainerRef) {
this.value = (viewContainerRef.constructor as any).name;
}
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => new Directive(directiveInject(ViewContainerRef as any)),
features: [PublicFeature],
exportAs: 'dir'
});
}
class DirectiveSameInstance {
isSameInstance: boolean;
constructor(viewContainerRef: ViewContainerRef, directive: Directive) {
this.isSameInstance = viewContainerRef === directive.viewContainerRef;
}
static ngDirectiveDef = defineDirective({
type: DirectiveSameInstance,
selectors: [['', 'dirSame', '']],
factory: () => new DirectiveSameInstance(
directiveInject(ViewContainerRef as any), directiveInject(Directive)),
exportAs: 'dirSame'
});
}
/**
* <div dir dirSame #dir="dir" #dirSame="dirSame">
* {{ dir.value }} - {{ dirSame.value }}
* </div>
*/
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(
0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
{ text(3); }
elementEnd();
}
if (rf & RenderFlags.Update) {
const tmp1 = reference(1) as any;
const tmp2 = reference(2) as any;
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.isSameInstance, ''));
}
}, 4, 2, [Directive, DirectiveSameInstance]);
const fixture = new ComponentFixture(App);
// Each ViewContainerRef instance should be unique
expect(fixture.html).toContain('ViewContainerRef');
expect(fixture.html).toContain('false');
});
});
describe('ChangeDetectorRef', () => {
let dir: Directive;
let dirSameInstance: DirectiveSameInstance;
let comp: MyComp;
class MyComp {
constructor(public cdr: ChangeDetectorRef) {}
static ngComponentDef = defineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: () => comp = new MyComp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 0,
template: function(rf: RenderFlags, ctx: MyComp) {
if (rf & RenderFlags.Create) {
projectionDef();
projection(0);
}
}
});
}
class Directive {
value: string;
constructor(public elementRef: ElementRef) {
this.value = (elementRef.constructor as any).name;
}
constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; }
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => dir = new Directive(injectElementRef()),
factory: () => dir = new Directive(directiveInject(ChangeDetectorRef as any)),
features: [PublicFeature],
exportAs: 'dir'
});
}
class DirectiveSameInstance {
isSameInstance: boolean;
constructor(public elementRef: ElementRef, directive: Directive) {
this.isSameInstance = elementRef === directive.elementRef;
}
constructor(public cdr: ChangeDetectorRef) {}
static ngDirectiveDef = defineDirective({
type: DirectiveSameInstance,
selectors: [['', 'dirSame', '']],
factory: () => dirSameInstance =
new DirectiveSameInstance(injectElementRef(), directiveInject(Directive)),
exportAs: 'dirSame'
new DirectiveSameInstance(directiveInject(ChangeDetectorRef as any))
});
}
/** <div dir dirSame></div> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', '']);
elementEnd();
divNode = load(0);
}
}, 1, 0, [Directive, DirectiveSameInstance]);
const directives = [MyComp, Directive, DirectiveSameInstance, NgIf];
const fixture = new ComponentFixture(App);
expect(dir.value).toEqual('ElementRef');
expect(dir.elementRef.nativeElement).toEqual(divNode.native);
expect(dirSameInstance.elementRef.nativeElement).toEqual(divNode.native);
it('should inject current component ChangeDetectorRef into directives on the same node as components',
() => {
/** <my-comp dir dirSameInstance #dir="dir"></my-comp> {{ dir.value }} */
const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'my-comp', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
text(2);
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}, 3, 1, directives);
// Each ElementRef instance should be unique
expect(dirSameInstance.isSameInstance).toBe(false);
});
const app = renderComponent(MyApp);
// ChangeDetectorRef is the token, ViewRef has historically been the constructor
expect(toHtml(app)).toEqual('<my-comp dir="" dirsame=""></my-comp>ViewRef');
expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp);
it('should create ElementRef with comment if requesting directive is on <ng-template> node',
() => {
let dir !: Directive;
let commentNode !: LContainerNode;
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(comp !.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
class Directive {
value: string;
constructor(public elementRef: ElementRef) {
this.value = (elementRef.constructor as any).name;
it('should inject host component ChangeDetectorRef into directives on normal elements',
() => {
class MyApp {
constructor(public cdr: ChangeDetectorRef) {}
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
consts: 3,
vars: 1,
factory: () => new MyApp(directiveInject(ChangeDetectorRef as any)),
/** <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
},
directives: directives
});
}
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => dir = new Directive(injectElementRef()),
features: [PublicFeature],
exportAs: 'dir'
});
}
/** <ng-template dir></ng-template> */
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, () => {}, 0, 0, null, ['dir', '']);
commentNode = load(0);
const app = renderComponent(MyApp);
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(app.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
it('should inject host component ChangeDetectorRef into directives in a component\'s ContentChildren',
() => {
class MyApp {
constructor(public cdr: ChangeDetectorRef) {}
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
consts: 4,
vars: 1,
factory: () => new MyApp(directiveInject(ChangeDetectorRef as any)),
/**
* <my-comp>
* <div dir dirSameInstance #dir="dir"></div>
* </my-comp>
* {{ dir.value }}
*/
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp');
{ element(1, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); }
elementEnd();
text(3);
}
if (rf & RenderFlags.Update) {
const tmp = reference(2) as any;
textBinding(3, bind(tmp.value));
}
},
directives: directives
});
}
}, 1, 0, [Directive]);
const fixture = new ComponentFixture(App);
expect(dir.value).toEqual('ElementRef');
expect(dir.elementRef.nativeElement).toEqual(commentNode.native);
});
});
const app = renderComponent(MyApp);
expect(toHtml(app)).toEqual('<my-comp><div dir="" dirsame=""></div></my-comp>ViewRef');
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
describe('TemplateRef', () => {
it('should create directive with TemplateRef dependencies', () => {
class Directive {
value: string;
constructor(public templateRef: TemplateRef<any>) {
this.value = (templateRef.constructor as any).name;
}
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => new Directive(injectTemplateRef()),
features: [PublicFeature],
exportAs: 'dir'
});
}
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(app !.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
class DirectiveSameInstance {
isSameInstance: boolean;
constructor(templateRef: TemplateRef<any>, directive: Directive) {
this.isSameInstance = templateRef === directive.templateRef;
}
static ngDirectiveDef = defineDirective({
type: DirectiveSameInstance,
selectors: [['', 'dirSame', '']],
factory: () => new DirectiveSameInstance(injectTemplateRef(), directiveInject(Directive)),
exportAs: 'dirSame'
});
}
it('should inject host component ChangeDetectorRef into directives in embedded views', () => {
/**
* <ng-template dir dirSame #dir="dir" #dirSame="dirSame">
* {{ dir.value }} - {{ dirSame.value }}
* </ng-template>
*/
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, function() {
}, 0, 0, undefined, ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
text(3);
}
if (rf & RenderFlags.Update) {
const tmp1 = reference(1) as any;
const tmp2 = reference(2) as any;
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.isSameInstance, ''));
}
}, 4, 2, [Directive, DirectiveSameInstance]);
class MyApp {
showing = true;
const fixture = new ComponentFixture(App);
// Each TemplateRef instance should be unique
expect(fixture.html).toEqual('TemplateRef-false');
});
});
constructor(public cdr: ChangeDetectorRef) {}
describe('ViewContainerRef', () => {
it('should create directive with ViewContainerRef dependencies', () => {
class Directive {
value: string;
constructor(public viewContainerRef: ViewContainerRef) {
this.value = (viewContainerRef.constructor as any).name;
}
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => new Directive(injectViewContainerRef()),
features: [PublicFeature],
exportAs: 'dir'
});
}
class DirectiveSameInstance {
isSameInstance: boolean;
constructor(viewContainerRef: ViewContainerRef, directive: Directive) {
this.isSameInstance = viewContainerRef === directive.viewContainerRef;
}
static ngDirectiveDef = defineDirective({
type: DirectiveSameInstance,
selectors: [['', 'dirSame', '']],
factory:
() => new DirectiveSameInstance(injectViewContainerRef(), directiveInject(Directive)),
exportAs: 'dirSame'
});
}
/**
* <div dir dirSame #dir="dir" #dirSame="dirSame">
* {{ dir.value }} - {{ dirSame.value }}
* </div>
*/
const App = createComponent('app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir', 'dirSame', 'dirSame']);
{ text(3); }
elementEnd();
}
if (rf & RenderFlags.Update) {
const tmp1 = reference(1) as any;
const tmp2 = reference(2) as any;
textBinding(3, interpolation2('', tmp1.value, '-', tmp2.isSameInstance, ''));
}
}, 4, 2, [Directive, DirectiveSameInstance]);
const fixture = new ComponentFixture(App);
// Each ViewContainerRef instance should be unique
expect(fixture.html).toEqual('<div dir="" dirsame="">ViewContainerRef-false</div>');
});
});
describe('ChangeDetectorRef', () => {
let dir: Directive;
let dirSameInstance: DirectiveSameInstance;
let comp: MyComp;
class MyComp {
constructor(public cdr: ChangeDetectorRef) {}
static ngComponentDef = defineComponent({
type: MyComp,
selectors: [['my-comp']],
factory: () => comp = new MyComp(injectChangeDetectorRef()),
consts: 1,
vars: 0,
template: function(rf: RenderFlags, ctx: MyComp) {
if (rf & RenderFlags.Create) {
projectionDef();
projection(0);
}
}
});
}
class Directive {
value: string;
constructor(public cdr: ChangeDetectorRef) { this.value = (cdr.constructor as any).name; }
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => dir = new Directive(injectChangeDetectorRef()),
features: [PublicFeature],
exportAs: 'dir'
});
}
class DirectiveSameInstance {
constructor(public cdr: ChangeDetectorRef) {}
static ngDirectiveDef = defineDirective({
type: DirectiveSameInstance,
selectors: [['', 'dirSame', '']],
factory: () => dirSameInstance = new DirectiveSameInstance(injectChangeDetectorRef())
});
}
const directives = [MyComp, Directive, DirectiveSameInstance, NgIf];
it('should inject current component ChangeDetectorRef into directives on the same node as components',
() => {
/** <my-comp dir dirSameInstance #dir="dir"></my-comp> {{ dir.value }} */
const MyApp = createComponent('my-app', function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
element(0, 'my-comp', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
text(2);
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}, 3, 1, directives);
const app = renderComponent(MyApp);
// ChangeDetectorRef is the token, ViewRef has historically been the constructor
expect(toHtml(app)).toEqual('<my-comp dir="" dirsame=""></my-comp>ViewRef');
expect((comp !.cdr as ViewRef<MyComp>).context).toBe(comp);
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(comp !.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
it('should inject host component ChangeDetectorRef into directives on normal elements', () => {
class MyApp {
constructor(public cdr: ChangeDetectorRef) {}
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
consts: 3,
vars: 1,
factory: () => new MyApp(injectChangeDetectorRef()),
/** <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
}
if (rf & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
},
directives: directives
});
}
const app = renderComponent(MyApp);
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(app.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
it('should inject host component ChangeDetectorRef into directives in a component\'s ContentChildren',
() => {
class MyApp {
constructor(public cdr: ChangeDetectorRef) {}
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
consts: 4,
vars: 1,
factory: () => new MyApp(injectChangeDetectorRef()),
/**
* <my-comp>
* <div dir dirSameInstance #dir="dir"></div>
* </my-comp>
* {{ dir.value }}
*/
template: function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
elementStart(0, 'my-comp');
{ element(1, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']); }
elementEnd();
text(3);
}
if (rf & RenderFlags.Update) {
const tmp = reference(2) as any;
textBinding(3, bind(tmp.value));
}
},
directives: directives
});
}
const app = renderComponent(MyApp);
expect(toHtml(app)).toEqual('<my-comp><div dir="" dirsame=""></div></my-comp>ViewRef');
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(app !.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
it('should inject host component ChangeDetectorRef into directives in embedded views', () => {
class MyApp {
showing = true;
constructor(public cdr: ChangeDetectorRef) {}
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()),
consts: 1,
vars: 0,
/**
* % if (showing) {
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 0,
/**
* % if (showing) {
* <div dir dirSameInstance #dir="dir"> {{ dir.value }} </div>
* % }
*/
template: function(rf: RenderFlags, ctx: MyApp) {
if (rf & RenderFlags.Create) {
container(0);
}
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
{
if (ctx.showing) {
let rf1 = embeddedViewStart(0, 3, 1);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}
embeddedViewEnd();
*/
template: function(rf: RenderFlags, ctx: MyApp) {
if (rf & RenderFlags.Create) {
container(0);
}
containerRefreshEnd();
}
},
directives: directives
});
}
const app = renderComponent(MyApp);
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(app.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
it('should inject host component ChangeDetectorRef into directives on containers', () => {
function C1(rf1: RenderFlags, ctx1: any) {
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
if (rf & RenderFlags.Update) {
containerRefreshStart(0);
{
if (ctx.showing) {
let rf1 = embeddedViewStart(0, 3, 1);
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}
embeddedViewEnd();
}
containerRefreshEnd();
}
},
directives: directives
});
}
if (rf1 & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
const app = renderComponent(MyApp);
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(app.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
it('should inject host component ChangeDetectorRef into directives on containers', () => {
function C1(rf1: RenderFlags, ctx1: any) {
if (rf1 & RenderFlags.Create) {
elementStart(0, 'div', ['dir', '', 'dirSame', ''], ['dir', 'dir']);
{ text(2); }
elementEnd();
}
if (rf1 & RenderFlags.Update) {
const tmp = reference(1) as any;
textBinding(2, bind(tmp.value));
}
}
}
class MyApp {
showing = true;
class MyApp {
showing = true;
constructor(public cdr: ChangeDetectorRef) {}
constructor(public cdr: ChangeDetectorRef) {}
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(injectChangeDetectorRef()),
consts: 1,
vars: 0,
/** <div *ngIf="showing" dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
template: function(rf: RenderFlags, ctx: MyApp) {
if (rf & RenderFlags.Create) {
template(0, C1, 3, 1, null, ['ngIf', 'showing']);
}
},
directives: directives
});
}
static ngComponentDef = defineComponent({
type: MyApp,
selectors: [['my-app']],
factory: () => new MyApp(directiveInject(ChangeDetectorRef as any)),
consts: 1,
vars: 0,
/** <div *ngIf="showing" dir dirSameInstance #dir="dir"> {{ dir.value }} </div> */
template: function(rf: RenderFlags, ctx: MyApp) {
if (rf & RenderFlags.Create) {
template(0, C1, 3, 1, null, ['ngIf', 'showing']);
}
},
directives: directives
});
}
const app = renderComponent(MyApp);
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
const app = renderComponent(MyApp);
expect(toHtml(app)).toEqual('<div dir="" dirsame="">ViewRef</div>');
expect((app !.cdr as ViewRef<MyApp>).context).toBe(app);
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(app.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
// Each ChangeDetectorRef instance should be unique
expect(dir !.cdr).not.toBe(app.cdr);
expect(dir !.cdr).not.toBe(dirSameInstance !.cdr);
});
});
});

View File

@ -10,8 +10,7 @@ import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
import {RenderFlags} from '@angular/core/src/render3';
import {RendererStyleFlags2, RendererType2} from '../../src/render/api';
import {createTemplateRef, getOrCreateNodeInjectorForNode} from '../../src/render3/di';
import {AttributeMarker, defineComponent, defineDirective, injectElementRef, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {AttributeMarker, defineComponent, defineDirective} from '../../src/render3/index';
import {NO_CHANGE, bind, container, containerRefreshEnd, containerRefreshStart, element, elementAttribute, elementClassProp, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, elementStyleProp, elementStyling, elementStylingApply, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation2, interpolation3, interpolation4, interpolation5, interpolation6, interpolation7, interpolation8, interpolationV, listener, load, loadDirective, projection, projectionDef, text, textBinding, template} from '../../src/render3/instructions';
import {InitialStylingFlags} from '../../src/render3/interfaces/definition';
@ -21,9 +20,10 @@ import {sanitizeUrl} from '../../src/sanitization/sanitization';
import {Sanitizer, SecurityContext} from '../../src/sanitization/security';
import {NgIf} from './common_with_def';
import {ComponentFixture, TemplateFixture, containerEl, createComponent, renderToHtml} from './render_util';
import {ComponentFixture, TemplateFixture, createComponent, renderToHtml} from './render_util';
import {MONKEY_PATCH_KEY_NAME, getContext} from '../../src/render3/context_discovery';
import {StylingIndex} from '../../src/render3/styling';
import {directiveInject} from '../../src/render3/di';
describe('render3 integration test', () => {
@ -649,7 +649,9 @@ describe('render3 integration test', () => {
static ngDirectiveDef = defineDirective({
type: TestDirective,
selectors: [['', 'testDirective', '']],
factory: () => new TestDirective(injectTemplateRef(), injectViewContainerRef()),
factory:
() => new TestDirective(
directiveInject(TemplateRef as any), directiveInject(ViewContainerRef as any)),
});
}
@ -754,7 +756,9 @@ describe('render3 integration test', () => {
static ngDirectiveDef = defineDirective({
type: TestDirective,
selectors: [['', 'testDirective', '']],
factory: () => new TestDirective(injectTemplateRef(), injectViewContainerRef()),
factory:
() => new TestDirective(
directiveInject(TemplateRef as any), directiveInject(ViewContainerRef as any)),
});
}
@ -822,7 +826,7 @@ describe('render3 integration test', () => {
static ngDirectiveDef = defineDirective({
type: Directive,
selectors: [['', 'dir', '']],
factory: () => new Directive(injectElementRef()),
factory: () => new Directive(directiveInject(ElementRef)),
});
}

View File

@ -11,7 +11,7 @@ import 'reflect-metadata';
import {InjectorDef, defineInjectable} from '@angular/core/src/di/defs';
import {Injectable} from '@angular/core/src/di/injectable';
import {inject, setCurrentInjector} from '@angular/core/src/di/injector';
import {ivyEnabled} from '@angular/core/src/ivy_switch';
import {ivyEnabled} from '@angular/core/src/ivy_switch/compiler/index';
import {Component, HostBinding, HostListener, Input, Output, Pipe} from '@angular/core/src/metadata/directives';
import {NgModule, NgModuleDefInternal} from '@angular/core/src/metadata/ng_module';
import {ComponentDefInternal, PipeDefInternal} from '@angular/core/src/render3/interfaces/definition';

View File

@ -10,11 +10,14 @@ import {NgForOfContext} from '@angular/common';
import {ElementRef, TemplateRef, ViewContainerRef} from '@angular/core';
import {EventEmitter} from '../..';
import {QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF, templateRefExtractor} from '../../src/render3/di';
import {AttributeMarker, QueryList, defineComponent, defineDirective, detectChanges, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {directiveInject} from '../../src/render3/di';
import {AttributeMarker, QueryList, defineComponent, defineDirective, detectChanges} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementContainerEnd, elementContainerStart, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, load, loadDirective, loadElement, loadQueryList, reference, registerContentQuery, template} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {query, queryRefresh} from '../../src/render3/query';
import {query, queryRefresh, QUERY_READ_CONTAINER_REF, QUERY_READ_ELEMENT_REF, QUERY_READ_FROM_NODE, QUERY_READ_TEMPLATE_REF} from '../../src/render3/query';
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility';
import {NgForOf, NgIf, NgTemplateOutlet} from './common_with_def';
import {ComponentFixture, TemplateFixture, createComponent, createDirective, renderComponent} from './render_util';
@ -118,7 +121,7 @@ describe('query', () => {
2, 0, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, Child, false, QUERY_READ_ELEMENT_REF);
query(0, Child, false, QUERY_READ_ELEMENT_REF(ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -226,7 +229,7 @@ describe('query', () => {
4, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_FROM_NODE);
query(0, ['foo'], false, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -263,8 +266,8 @@ describe('query', () => {
6, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_FROM_NODE);
query(1, ['bar'], false, QUERY_READ_FROM_NODE);
query(0, ['foo'], false, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
query(1, ['bar'], false, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -312,7 +315,7 @@ describe('query', () => {
6, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE);
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -349,7 +352,7 @@ describe('query', () => {
4, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF);
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF(ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -385,7 +388,7 @@ describe('query', () => {
3, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF);
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF(ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -421,7 +424,7 @@ describe('query', () => {
3, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -485,8 +488,8 @@ describe('query', () => {
5, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_ELEMENT_REF);
query(1, ['foo'], false, QUERY_READ_ELEMENT_REF);
query(0, ['foo'], true, QUERY_READ_ELEMENT_REF(ElementRef));
query(1, ['foo'], false, QUERY_READ_ELEMENT_REF(ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -520,7 +523,7 @@ describe('query', () => {
3, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_CONTAINER_REF);
query(0, ['foo'], false, QUERY_READ_CONTAINER_REF(ViewContainerRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -551,7 +554,7 @@ describe('query', () => {
3, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_CONTAINER_REF);
query(0, ['foo'], false, QUERY_READ_CONTAINER_REF(ViewContainerRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -584,7 +587,7 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF);
query(0, ['foo'], false, QUERY_READ_ELEMENT_REF(ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -618,7 +621,7 @@ describe('query', () => {
3, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], undefined, QUERY_READ_FROM_NODE);
query(0, ['foo'], undefined, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -650,7 +653,7 @@ describe('query', () => {
3, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_TEMPLATE_REF);
query(0, ['foo'], false, QUERY_READ_TEMPLATE_REF(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -687,7 +690,7 @@ describe('query', () => {
3, 0, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -732,7 +735,7 @@ describe('query', () => {
3, 0, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -770,7 +773,7 @@ describe('query', () => {
3, 0, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -810,7 +813,7 @@ describe('query', () => {
4, 0, [Child1, Child2], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE);
query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -849,8 +852,8 @@ describe('query', () => {
5, 0, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(1, ['bar'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
query(1, ['bar'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -893,7 +896,7 @@ describe('query', () => {
3, 0, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], undefined, QUERY_READ_ELEMENT_REF);
query(0, ['foo'], undefined, QUERY_READ_ELEMENT_REF(ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -931,7 +934,7 @@ describe('query', () => {
4, 0, [Child], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE);
query(0, ['foo', 'bar'], undefined, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -993,7 +996,7 @@ describe('query', () => {
selectors: [['', 'vc', '']],
factory: () => {
const directiveInstance =
new ViewContainerManipulatorDirective(injectViewContainerRef());
new ViewContainerManipulatorDirective(directiveInject(ViewContainerRef as any));
directiveInstances.push(directiveInstance);
return directiveInstance;
}
@ -1039,7 +1042,7 @@ describe('query', () => {
3, 1, [NgIf], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1100,7 +1103,7 @@ describe('query', () => {
viewQuery: function(rf: RenderFlags, ctx: Cmpt) {
let tmp: any;
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) && (ctx.query = tmp as QueryList<any>);
@ -1170,10 +1173,12 @@ describe('query', () => {
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(
1, Cmpt_Template_1, 2, 1, null, null, ['tpl1', ''], templateRefExtractor);
1, Cmpt_Template_1, 2, 1, null, null, ['tpl1', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(3, 'div', ['id', 'middle'], ['foo', '']);
template(
5, Cmpt_Template_5, 2, 1, null, null, ['tpl2', ''], templateRefExtractor);
5, Cmpt_Template_5, 2, 1, null, null, ['tpl2', ''],
templateRefExtractor(TemplateRef, ElementRef));
template(7, null, 0, 0, null, [AttributeMarker.SelectOnly, 'vc']);
}
@ -1186,7 +1191,7 @@ describe('query', () => {
9, 0, [ViewContainerManipulatorDirective], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1268,7 +1273,9 @@ describe('query', () => {
template: function(rf: RenderFlags, ctx: any) {
let tmp: any;
if (rf & RenderFlags.Create) {
template(1, Cmpt_Template_1, 2, 1, null, [], ['tpl', ''], templateRefExtractor);
template(
1, Cmpt_Template_1, 2, 1, null, [], ['tpl', ''],
templateRefExtractor(TemplateRef, ElementRef));
template(3, null, 0, 0, null, [AttributeMarker.SelectOnly, 'vc']);
template(4, null, 0, 0, null, [AttributeMarker.SelectOnly, 'vc']);
}
@ -1281,7 +1288,7 @@ describe('query', () => {
viewQuery: (rf: RenderFlags, cmpt: Cmpt) => {
let tmp: any;
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) &&
@ -1341,7 +1348,7 @@ describe('query', () => {
if (rf & RenderFlags.Create) {
template(
1, MyApp_Template_1, 2, 0, undefined, undefined, ['tpl', ''],
templateRefExtractor);
templateRefExtractor(TemplateRef, ElementRef));
template(3, null, 0, 0, null, [AttributeMarker.SelectOnly, 'ngTemplateOutlet']);
}
if (rf & RenderFlags.Update) {
@ -1353,7 +1360,7 @@ describe('query', () => {
viewQuery: (rf: RenderFlags, myApp: MyApp) => {
let tmp: any;
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
queryRefresh(tmp = load<QueryList<any>>(0)) &&
@ -1418,7 +1425,7 @@ describe('query', () => {
2, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1483,7 +1490,7 @@ describe('query', () => {
6, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1560,7 +1567,7 @@ describe('query', () => {
2, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1640,7 +1647,7 @@ describe('query', () => {
2, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1709,8 +1716,8 @@ describe('query', () => {
5, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(1, ['foo'], false, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
query(1, ['foo'], false, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1790,7 +1797,7 @@ describe('query', () => {
2, 0, [], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], false, QUERY_READ_FROM_NODE);
query(0, ['foo'], false, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1844,7 +1851,8 @@ describe('query', () => {
static ngDirectiveDef = defineDirective({
type: SomeDir,
selectors: [['', 'someDir', '']],
factory: () => new SomeDir(injectViewContainerRef(), injectTemplateRef())
factory: () => new SomeDir(
directiveInject(ViewContainerRef as any), directiveInject(TemplateRef as any))
});
}
@ -1870,7 +1878,7 @@ describe('query', () => {
4, 0, [SomeDir], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo'], true, QUERY_READ_FROM_NODE);
query(0, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -1907,8 +1915,10 @@ describe('query', () => {
type: WithContentDirective,
selectors: [['', 'with-content', '']],
factory: () => new WithContentDirective(),
contentQueries:
() => { registerContentQuery(query(null, ['foo'], true, QUERY_READ_FROM_NODE)); },
contentQueries: () => {
registerContentQuery(
query(null, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef)));
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
withContentInstance = loadDirective<WithContentDirective>(dirIndex);
@ -1929,8 +1939,10 @@ describe('query', () => {
template: function(rf: RenderFlags, ctx: any) {},
consts: 0,
vars: 0,
contentQueries:
() => { registerContentQuery(query(null, ['foo'], false, QUERY_READ_FROM_NODE)); },
contentQueries: () => {
registerContentQuery(
query(null, ['foo'], false, QUERY_READ_FROM_NODE(TemplateRef, ElementRef)));
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
shallowCompInstance = loadDirective<ShallowComp>(dirIndex);
@ -2046,7 +2058,7 @@ describe('query', () => {
6, 0, [WithContentDirective], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE);
query(0, ['foo', 'bar'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -2086,7 +2098,7 @@ describe('query', () => {
6, 0, [WithContentDirective], [],
function(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
query(0, ['bar'], true, QUERY_READ_FROM_NODE);
query(0, ['bar'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef));
}
if (rf & RenderFlags.Update) {
let tmp: any;
@ -2110,7 +2122,8 @@ describe('query', () => {
contentQueries: () => {
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
// QueryList<ElementRef>;
registerContentQuery(query(null, ['foo', 'bar', 'baz'], true, QUERY_READ_FROM_NODE));
registerContentQuery(query(
null, ['foo', 'bar', 'baz'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef)));
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
@ -2174,7 +2187,8 @@ describe('query', () => {
contentQueries: () => {
// @ContentChildren('foo, bar, baz', {descendants: true}) fooBars:
// QueryList<ElementRef>;
registerContentQuery(query(null, ['foo'], false, QUERY_READ_FROM_NODE));
registerContentQuery(
query(null, ['foo'], false, QUERY_READ_FROM_NODE(TemplateRef, ElementRef)));
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
@ -2227,7 +2241,8 @@ describe('query', () => {
factory: () => new ShallowQueryDirective(),
contentQueries: () => {
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
registerContentQuery(query(null, ['foo'], false, QUERY_READ_FROM_NODE));
registerContentQuery(
query(null, ['foo'], false, QUERY_READ_FROM_NODE(TemplateRef, ElementRef)));
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;
@ -2247,7 +2262,8 @@ describe('query', () => {
factory: () => new DeepQueryDirective(),
contentQueries: () => {
// @ContentChildren('foo', {descendants: false}) foos: QueryList<ElementRef>;
registerContentQuery(query(null, ['foo'], true, QUERY_READ_FROM_NODE));
registerContentQuery(
query(null, ['foo'], true, QUERY_READ_FROM_NODE(TemplateRef, ElementRef)));
},
contentQueriesRefresh: (dirIndex: number, queryStartIdx: number) => {
let tmp: any;

View File

@ -6,13 +6,19 @@
* found in the LICENSE file at https://angular.io/license
*/
import {ChangeDetectorRef} from '@angular/core/src/change_detection/change_detector_ref';
import {ElementRef} from '@angular/core/src/linker/element_ref';
import {TemplateRef} from '@angular/core/src/linker/template_ref';
import {ViewContainerRef} from '@angular/core/src/linker/view_container_ref';
import {stringifyElement} from '@angular/platform-browser/testing/src/browser_util';
import {Injector} from '../../src/di/injector';
import {R3_CHANGE_DETECTOR_REF_FACTORY, R3_ELEMENT_REF_FACTORY, R3_TEMPLATE_REF_FACTORY, R3_VIEW_CONTAINER_REF_FACTORY} from '../../src/ivy_switch/runtime/ivy_switch_on';
import {PlayerHandler} from '../../src/render3/animations/interfaces';
import {CreateComponentOptions} from '../../src/render3/component';
import {getContext, isComponentInstance} from '../../src/render3/context_discovery';
import {extractDirectiveDef, extractPipeDef} from '../../src/render3/definition';
import {NG_ELEMENT_ID} from '../../src/render3/fields';
import {ComponentTemplate, ComponentType, DirectiveDefInternal, DirectiveType, PublicFeature, RenderFlags, defineComponent, defineDirective, renderComponent as _renderComponent, tick} from '../../src/render3/index';
import {renderTemplate} from '../../src/render3/instructions';
import {DirectiveDefList, DirectiveTypesOrFactory, PipeDefInternal, PipeDefList, PipeTypesOrFactory} from '../../src/render3/interfaces/definition';
@ -208,6 +214,10 @@ function toDefs(
beforeEach(resetDOM);
// This is necessary so we can switch between the Render2 version and the Ivy version
// of special objects like ElementRef and TemplateRef.
beforeEach(enableIvyInjectableFactories);
/**
* @deprecated use `TemplateFixture` or `ComponentFixture`
*/
@ -285,3 +295,17 @@ export function createDirective(
export const renderer: Renderer3 = null as any as Document;
export const element: RElement = null as any as HTMLElement;
export const text: RText = null as any as Text;
/**
* Switches between Render2 version of special objects like ElementRef and the Ivy version
* of these objects. It's necessary to keep them separate so that we don't pull in fns
* like injectElementRef() prematurely.
*/
export function enableIvyInjectableFactories() {
(ElementRef as any)[NG_ELEMENT_ID] = () => R3_ELEMENT_REF_FACTORY(ElementRef);
(TemplateRef as any)[NG_ELEMENT_ID] = () => R3_TEMPLATE_REF_FACTORY(TemplateRef, ElementRef);
(ViewContainerRef as any)[NG_ELEMENT_ID] = () =>
R3_VIEW_CONTAINER_REF_FACTORY(ViewContainerRef, ElementRef);
(ChangeDetectorRef as any)[NG_ELEMENT_ID] = () => R3_CHANGE_DETECTOR_REF_FACTORY();
}

View File

@ -8,11 +8,12 @@
import {Component, ComponentFactoryResolver, ElementRef, EmbeddedViewRef, NgModuleRef, Pipe, PipeTransform, RendererFactory2, TemplateRef, ViewContainerRef, createInjector, defineInjector, ɵAPP_ROOT as APP_ROOT, ɵNgModuleDef as NgModuleDef} from '../../src/core';
import {ViewEncapsulation} from '../../src/metadata';
import {templateRefExtractor} from '../../src/render3/di';
import {AttributeMarker, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver, injectTemplateRef, injectViewContainerRef} from '../../src/render3/index';
import {directiveInject} from '../../src/render3/di';
import {AttributeMarker, NgOnChangesFeature, defineComponent, defineDirective, definePipe, injectComponentFactoryResolver} from '../../src/render3/index';
import {bind, container, containerRefreshEnd, containerRefreshStart, element, elementEnd, elementProperty, elementStart, embeddedViewEnd, embeddedViewStart, interpolation1, interpolation3, loadDirective, nextContext, projection, projectionDef, reference, template, text, textBinding} from '../../src/render3/instructions';
import {RenderFlags} from '../../src/render3/interfaces/definition';
import {templateRefExtractor} from '../../src/render3/view_engine_compatibility';
import {NgModuleFactory} from '../../src/render3/ng_module_ref';
import {pipe, pipeBind1} from '../../src/render3/pipe';
import {NgForOf} from '../../test/render3/common_with_def';
@ -23,7 +24,7 @@ import {ComponentFixture, TemplateFixture, createComponent} from './render_util'
describe('ViewContainerRef', () => {
let directiveInstance: DirectiveWithVCRef|null;
beforeEach(() => { directiveInstance = null; });
beforeEach(() => directiveInstance = null);
class DirectiveWithVCRef {
static ngDirectiveDef = defineDirective({
@ -31,7 +32,7 @@ describe('ViewContainerRef', () => {
selectors: [['', 'vcref', '']],
factory: () => directiveInstance = new DirectiveWithVCRef(
injectViewContainerRef(), injectComponentFactoryResolver()),
directiveInject(ViewContainerRef as any), injectComponentFactoryResolver()),
inputs: {tplRef: 'tplRef'}
});
@ -66,7 +67,9 @@ describe('ViewContainerRef', () => {
* <p vcref [tplRef]="tplRef"></p>
*/
function createTemplate() {
template(0, embeddedTemplate, 1, 1, null, null, ['tplRef', ''], templateRefExtractor);
template(
0, embeddedTemplate, 1, 1, null, null, ['tplRef', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'p', ['vcref', '']);
}
@ -83,7 +86,9 @@ describe('ViewContainerRef', () => {
* <footer></footer>
*/
function createTemplate() {
template(0, embeddedTemplate, 1, 1, null, null, ['tplRef', ''], templateRefExtractor);
template(
0, embeddedTemplate, 1, 1, null, null, ['tplRef', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'header', ['vcref', '']);
element(3, 'footer');
}
@ -119,7 +124,9 @@ describe('ViewContainerRef', () => {
* <footer></footer>
*/
function createTemplate() {
template(0, embeddedTemplate, 1, 1, null, [], ['tplRef', ''], templateRefExtractor);
template(
0, embeddedTemplate, 1, 1, null, [], ['tplRef', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'header-cmp', ['vcref', '']);
element(3, 'footer');
}
@ -155,7 +162,9 @@ describe('ViewContainerRef', () => {
* <div vcref [tplRef]="tplRef"></div>
*/
function createTemplate() {
template(0, embeddedTemplate, 1, 1, null, null, ['tplRef', ''], templateRefExtractor);
template(
0, embeddedTemplate, 1, 1, null, null, ['tplRef', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'div', ['vcref', '']);
element(3, 'div', ['vcref', '']);
@ -186,7 +195,8 @@ describe('ViewContainerRef', () => {
*/
function createTemplate() {
template(
0, embeddedTemplate, 1, 1, null, ['vcref', ''], ['tplRef', ''], templateRefExtractor);
0, embeddedTemplate, 1, 1, null, ['vcref', ''], ['tplRef', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'footer');
}
@ -225,7 +235,8 @@ describe('ViewContainerRef', () => {
type: TestDirective,
selectors: [['', 'testdir', '']],
factory: () => {
const instance = new TestDirective(injectViewContainerRef(), injectTemplateRef());
const instance = new TestDirective(
directiveInject(ViewContainerRef as any), directiveInject(TemplateRef as any));
directiveInstances.push(instance);
@ -299,8 +310,9 @@ describe('ViewContainerRef', () => {
static ngDirectiveDef = defineDirective({
type: TestDirective,
selectors: [['', 'testdir', '']],
factory: () => directiveInstance =
new TestDirective(injectViewContainerRef(), injectTemplateRef())
factory: () => directiveInstance = new TestDirective(
directiveInject(ViewContainerRef as any),
directiveInject(TemplateRef as any))
});
constructor(private _vcRef: ViewContainerRef, private _tplRef: TemplateRef<{}>) {}
@ -455,7 +467,8 @@ describe('ViewContainerRef', () => {
template: (rf: RenderFlags, cmp: SomeComponent) => {
if (rf & RenderFlags.Create) {
template(
0, SomeComponent_Template_0, 2, 3, null, [], ['foo', ''], templateRefExtractor);
0, SomeComponent_Template_0, 2, 3, null, [], ['foo', ''],
templateRefExtractor(TemplateRef, ElementRef));
pipe(2, 'starPipe');
element(3, 'child', ['vcref', '']);
pipe(4, 'starPipe');
@ -495,7 +508,7 @@ describe('ViewContainerRef', () => {
static ngDirectiveDef = defineDirective({
type: InsertionDir,
selectors: [['', 'tplDir', '']],
factory: () => new InsertionDir(injectViewContainerRef()),
factory: () => new InsertionDir(directiveInject(ViewContainerRef as any)),
inputs: {tplDir: 'tplDir'}
});
}
@ -546,7 +559,9 @@ describe('ViewContainerRef', () => {
*/
const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) {
if (rf & RenderFlags.Create) {
template(0, fooTemplate, 2, 1, null, null, ['foo', ''], templateRefExtractor);
template(
0, fooTemplate, 2, 1, null, null, ['foo', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'child');
}
@ -637,7 +652,9 @@ describe('ViewContainerRef', () => {
*/
const Parent = createComponent('parent', function(rf: RenderFlags, parent: any) {
if (rf & RenderFlags.Create) {
template(0, rowTemplate, 3, 2, null, null, ['rowTemplate', ''], templateRefExtractor);
template(
0, rowTemplate, 3, 2, null, null, ['rowTemplate', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'loop-comp');
}
@ -651,7 +668,9 @@ describe('ViewContainerRef', () => {
function rowTemplate(rf: RenderFlags, ctx: any) {
if (rf & RenderFlags.Create) {
template(0, cellTemplate, 2, 3, null, null, ['cellTemplate', ''], templateRefExtractor);
template(
0, cellTemplate, 2, 3, null, null, ['cellTemplate', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'loop-comp');
}
@ -1196,7 +1215,9 @@ describe('ViewContainerRef', () => {
vars: 2,
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
template(0, embeddedTemplate, 2, 1, null, null, ['foo', ''], templateRefExtractor);
template(
0, embeddedTemplate, 2, 1, null, null, ['foo', ''],
templateRefExtractor(TemplateRef, ElementRef));
elementStart(2, 'child');
{
elementStart(3, 'header', ['vcref', '']);
@ -1291,7 +1312,8 @@ describe('ViewContainerRef', () => {
template: (rf: RenderFlags, cmp: Parent) => {
if (rf & RenderFlags.Create) {
template(
0, embeddedTemplate, 2, 1, null, undefined, ['foo', ''], templateRefExtractor);
0, embeddedTemplate, 2, 1, null, undefined, ['foo', ''],
templateRefExtractor(TemplateRef, ElementRef));
elementStart(2, 'child-with-view');
text(3, 'Before projected');
elementStart(4, 'header', ['vcref', '']);
@ -1375,7 +1397,8 @@ describe('ViewContainerRef', () => {
let tplRef: any;
if (rf & RenderFlags.Create) {
template(
0, embeddedTemplate, 2, 1, null, null, ['foo', ''], templateRefExtractor);
0, embeddedTemplate, 2, 1, null, null, ['foo', ''],
templateRefExtractor(TemplateRef, ElementRef));
elementStart(2, 'child-with-selector');
elementStart(3, 'header', ['vcref', '']);
text(4, 'blah');
@ -1428,7 +1451,8 @@ describe('ViewContainerRef', () => {
let tplRef: any;
if (rf & RenderFlags.Create) {
template(
0, embeddedTemplate, 2, 1, null, null, ['foo', ''], templateRefExtractor);
0, embeddedTemplate, 2, 1, null, null, ['foo', ''],
templateRefExtractor(TemplateRef, ElementRef));
elementStart(2, 'child-with-selector');
elementStart(3, 'footer', ['vcref', '']);
text(4, 'blah');
@ -1533,7 +1557,8 @@ describe('ViewContainerRef', () => {
template: (rf: RenderFlags, cmp: SomeComponent) => {
if (rf & RenderFlags.Create) {
template(
0, SomeComponent_Template_0, 1, 1, null, [], ['foo', ''], templateRefExtractor);
0, SomeComponent_Template_0, 1, 1, null, [], ['foo', ''],
templateRefExtractor(TemplateRef, ElementRef));
element(2, 'hooks', ['vcref', '']);
element(3, 'hooks');
}