From efbd446d18e6e0380beafcad6e94a7751d788623 Mon Sep 17 00:00:00 2001
From: Tobias Bosch
Date: Mon, 18 Apr 2016 13:24:42 -0700
Subject: [PATCH] refactor(core): add `Query.read` and remove
`DynamicComponentLoader.loadIntoLocation`.
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This adds the feature for `@ViewChild`/`@ViewChildren`/`@ContentChild`/`@ContentChildren` to define what to read from the queried element.
E.g. `@ViewChild(`someVar`, read: ViewContainerRef)` will locate the element with a variable `someVar` on it and return a `ViewContainerRef` for it.
Background: With this change, Angular knows exactly at which elements there will be `ViewConainerRef`s as the user has to ask explicitly of them. This simplifies codegen and will make converting Angular templates into server side templates simpler as well.
BREAKING CHANGE:
- `DynamicComponentLoader.loadIntoLocation` has been removed. Use `@ViewChild(‘myVar’, read: ViewContainerRef)` to get hold of a `ViewContainerRef` at an element with variable `myVar`.
- `DynamicComponentLoader.loadNextToLocation` now takes a `ViewContainerRef` instead of an `ElementRef`.
- `AppViewManager` is renamed into `ViewUtils` and is a mere private utility service.
---
.../angular2/src/compiler/compile_metadata.ts | 20 +-
modules/angular2/src/compiler/identifiers.ts | 12 +-
.../angular2/src/compiler/provider_parser.ts | 70 ++--
.../angular2/src/compiler/runtime_compiler.ts | 4 +-
.../angular2/src/compiler/runtime_metadata.ts | 3 +-
modules/angular2/src/compiler/template_ast.ts | 9 +-
.../angular2/src/compiler/template_parser.ts | 20 +-
.../compiler/view_compiler/compile_element.ts | 153 ++++----
.../compiler/view_compiler/compile_query.ts | 2 +-
.../compiler/view_compiler/compile_view.ts | 2 +-
.../src/compiler/view_compiler/constants.ts | 4 +-
.../compiler/view_compiler/event_binder.ts | 7 +-
.../compiler/view_compiler/property_binder.ts | 3 +-
.../compiler/view_compiler/view_builder.ts | 76 ++--
.../src/core/application_common_providers.ts | 5 +-
modules/angular2/src/core/linker.ts | 1 -
.../src/core/linker/component_factory.ts | 22 +-
.../core/linker/dynamic_component_loader.ts | 82 +---
modules/angular2/src/core/linker/element.ts | 23 +-
.../angular2/src/core/linker/element_ref.ts | 14 +-
.../angular2/src/core/linker/template_ref.ts | 6 +-
modules/angular2/src/core/linker/view.ts | 15 +-
.../src/core/linker/view_container_ref.ts | 9 +-
.../angular2/src/core/linker/view_manager.ts | 77 ----
.../angular2/src/core/linker/view_utils.ts | 26 ++
modules/angular2/src/core/metadata.dart | 19 +-
modules/angular2/src/core/metadata.ts | 23 +-
modules/angular2/src/core/metadata/di.ts | 30 +-
.../directives/router_link_transform.ts | 4 +-
.../src/router/directives/router_outlet.ts | 6 +-
modules/angular2/src/upgrade/constants.ts | 1 -
.../src/upgrade/downgrade_ng2_adapter.ts | 4 +-
.../angular2/src/upgrade/upgrade_adapter.ts | 13 +-
.../test/compiler/template_parser_spec.ts | 6 +-
.../linker/dynamic_component_loader_spec.ts | 350 +++++-------------
.../core/linker/query_integration_spec.ts | 141 ++++++-
.../linker/view_injector_integration_spec.ts | 2 +-
modules/angular2/test/public_api_spec.ts | 1 -
.../integration/impl/fixture_components.ts | 12 +-
.../worker/renderer_integration_spec.ts | 17 +-
modules/benchmarks/src/costs/index.ts | 4 +-
tools/public_api_guard/public_api_spec.ts | 27 +-
42 files changed, 608 insertions(+), 717 deletions(-)
delete mode 100644 modules/angular2/src/core/linker/view_manager.ts
diff --git a/modules/angular2/src/compiler/compile_metadata.ts b/modules/angular2/src/compiler/compile_metadata.ts
index 3c8ed69bf6..4be4e5e215 100644
--- a/modules/angular2/src/compiler/compile_metadata.ts
+++ b/modules/angular2/src/compiler/compile_metadata.ts
@@ -13,7 +13,12 @@ import {
isArray
} from 'angular2/src/facade/lang';
import {unimplemented, BaseException} from 'angular2/src/facade/exceptions';
-import {StringMapWrapper, MapWrapper, SetWrapper} from 'angular2/src/facade/collection';
+import {
+ StringMapWrapper,
+ MapWrapper,
+ SetWrapper,
+ ListWrapper
+} from 'angular2/src/facade/collection';
import {
ChangeDetectionStrategy,
CHANGE_DETECTION_STRATEGY_VALUES
@@ -414,17 +419,20 @@ export class CompileQueryMetadata {
descendants: boolean;
first: boolean;
propertyName: string;
+ read: CompileTokenMetadata;
- constructor({selectors, descendants, first, propertyName}: {
+ constructor({selectors, descendants, first, propertyName, read}: {
selectors?: Array,
descendants?: boolean,
first?: boolean,
- propertyName?: string
+ propertyName?: string,
+ read?: CompileTokenMetadata
} = {}) {
this.selectors = selectors;
this.descendants = normalizeBool(descendants);
this.first = normalizeBool(first);
this.propertyName = propertyName;
+ this.read = read;
}
static fromJson(data: {[key: string]: any}): CompileQueryMetadata {
@@ -432,7 +440,8 @@ export class CompileQueryMetadata {
selectors: _arrayFromJson(data['selectors'], CompileTokenMetadata.fromJson),
descendants: data['descendants'],
first: data['first'],
- propertyName: data['propertyName']
+ propertyName: data['propertyName'],
+ read: _objFromJson(data['read'], CompileTokenMetadata.fromJson)
});
}
@@ -441,7 +450,8 @@ export class CompileQueryMetadata {
'selectors': _arrayToJson(this.selectors),
'descendants': this.descendants,
'first': this.first,
- 'propertyName': this.propertyName
+ 'propertyName': this.propertyName,
+ 'read': _objToJson(this.read)
};
}
}
diff --git a/modules/angular2/src/compiler/identifiers.ts b/modules/angular2/src/compiler/identifiers.ts
index f247a37cf5..453ed25ce4 100644
--- a/modules/angular2/src/compiler/identifiers.ts
+++ b/modules/angular2/src/compiler/identifiers.ts
@@ -2,6 +2,7 @@ import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadat
import {AppView} from 'angular2/src/core/linker/view';
import {StaticNodeDebugInfo, DebugContext} from 'angular2/src/core/linker/debug_context';
import {
+ ViewUtils,
flattenNestedViewRenderNodes,
interpolate,
checkBinding
@@ -15,7 +16,6 @@ import {
ChangeDetectorState,
ChangeDetectionStrategy
} from 'angular2/src/core/change_detection/change_detection';
-import {AppViewManager_} from 'angular2/src/core/linker/view_manager';
import {AppElement} from 'angular2/src/core/linker/element';
import {ElementRef} from 'angular2/src/core/linker/element_ref';
import {ViewContainerRef} from 'angular2/src/core/linker/view_container_ref';
@@ -34,7 +34,7 @@ var CD_MODULE_URL = 'asset:angular2/lib/src/core/change_detection/change_detecti
// Reassign the imports to different variables so we can
// define static variables with the name of the import.
// (only needed for Dart).
-var impAppViewManager_ = AppViewManager_;
+var impViewUtils = ViewUtils;
var impAppView = AppView;
var impDebugContext = DebugContext;
var impAppElement = AppElement;
@@ -61,10 +61,10 @@ var impInterpolate = interpolate;
var impCheckBinding = checkBinding;
export class Identifiers {
- static AppViewManager_ = new CompileIdentifierMetadata({
- name: 'AppViewManager_',
- moduleUrl: 'asset:angular2/lib/src/core/linker/view_manager' + MODULE_SUFFIX,
- runtime: impAppViewManager_
+ static ViewUtils = new CompileIdentifierMetadata({
+ name: 'ViewUtils',
+ moduleUrl: 'asset:angular2/lib/src/core/linker/view_utils' + MODULE_SUFFIX,
+ runtime: impViewUtils
});
static AppView = new CompileIdentifierMetadata(
{name: 'AppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: impAppView});
diff --git a/modules/angular2/src/compiler/provider_parser.ts b/modules/angular2/src/compiler/provider_parser.ts
index 4dc92e918d..5a9788a211 100644
--- a/modules/angular2/src/compiler/provider_parser.ts
+++ b/modules/angular2/src/compiler/provider_parser.ts
@@ -65,28 +65,42 @@ export class ProviderElementContext {
private _seenProviders = new CompileTokenMap();
private _allProviders: CompileTokenMap;
private _attrs: {[key: string]: string};
+ private _hasViewContainer: boolean = false;
constructor(private _viewContext: ProviderViewContext, private _parent: ProviderElementContext,
private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[],
- attrs: AttrAst[], private _sourceSpan: ParseSourceSpan) {
+ attrs: AttrAst[], vars: VariableAst[], private _sourceSpan: ParseSourceSpan) {
this._attrs = {};
attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
this._allProviders =
_resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors);
this._contentQueries = _getContentQueries(directivesMeta);
+ var queriedTokens = new CompileTokenMap();
+ this._allProviders.values().forEach(
+ (provider) => { this._addQueryReadsTo(provider.token, queriedTokens); });
+ vars.forEach((varAst) => {
+ var varToken = new CompileTokenMetadata({value: varAst.name});
+ this._addQueryReadsTo(varToken, queriedTokens);
+ });
+ if (isPresent(queriedTokens.get(identifierToken(Identifiers.ViewContainerRef)))) {
+ this._hasViewContainer = true;
+ }
+
// create the providers that we know are eager first
this._allProviders.values().forEach((provider) => {
- if (provider.eager || this.isQueried(provider.token)) {
- this._getLocalProvider(provider.providerType, provider.token, true);
+ var eager = provider.eager || isPresent(queriedTokens.get(provider.token));
+ if (eager) {
+ this._getOrCreateLocalProvider(provider.providerType, provider.token, true);
}
});
}
afterElement() {
// collect lazy providers
- this._allProviders.values().forEach(
- (provider) => { this._getLocalProvider(provider.providerType, provider.token, false); });
+ this._allProviders.values().forEach((provider) => {
+ this._getOrCreateLocalProvider(provider.providerType, provider.token, false);
+ });
}
get transformProviders(): ProviderAst[] { return this._transformedProviders.values(); }
@@ -101,30 +115,42 @@ export class ProviderElementContext {
return sortedDirectives;
}
- private isQueried(token: CompileTokenMetadata): boolean {
+ get transformedHasViewContainer(): boolean { return this._hasViewContainer; }
+
+ private _addQueryReadsTo(token: CompileTokenMetadata, queryReadTokens: CompileTokenMap) {
+ this._getQueriesFor(token).forEach((query) => {
+ var queryReadToken = isPresent(query.read) ? query.read : token;
+ if (isBlank(queryReadTokens.get(queryReadToken))) {
+ queryReadTokens.add(queryReadToken, true);
+ }
+ });
+ }
+
+ private _getQueriesFor(token: CompileTokenMetadata): CompileQueryMetadata[] {
+ var result: CompileQueryMetadata[] = [];
var currentEl: ProviderElementContext = this;
var distance = 0;
+ var queries: CompileQueryMetadata[];
while (currentEl !== null) {
- var localQueries = currentEl._contentQueries.get(token);
- if (isPresent(localQueries)) {
- if (localQueries.some((query) => query.descendants || distance <= 1)) {
- return true;
- }
+ queries = currentEl._contentQueries.get(token);
+ if (isPresent(queries)) {
+ ListWrapper.addAll(result, queries.filter((query) => query.descendants || distance <= 1));
}
if (currentEl._directiveAsts.length > 0) {
distance++;
}
currentEl = currentEl._parent;
}
- if (isPresent(this._viewContext.viewQueries.get(token))) {
- return true;
+ queries = this._viewContext.viewQueries.get(token);
+ if (isPresent(queries)) {
+ ListWrapper.addAll(result, queries);
}
- return false;
+ return result;
}
- private _getLocalProvider(requestingProviderType: ProviderAstType, token: CompileTokenMetadata,
- eager: boolean): ProviderAst {
+ private _getOrCreateLocalProvider(requestingProviderType: ProviderAstType,
+ token: CompileTokenMetadata, eager: boolean): ProviderAst {
var resolvedProvider = this._allProviders.get(token);
if (isBlank(resolvedProvider) ||
((requestingProviderType === ProviderAstType.Directive ||
@@ -198,17 +224,19 @@ export class ProviderElementContext {
if (dep.token.equalsTo(identifierToken(Identifiers.Renderer)) ||
dep.token.equalsTo(identifierToken(Identifiers.ElementRef)) ||
dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef)) ||
- dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef)) ||
dep.token.equalsTo(identifierToken(Identifiers.TemplateRef))) {
return dep;
}
+ if (dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef))) {
+ this._hasViewContainer = true;
+ }
}
// access the injector
if (dep.token.equalsTo(identifierToken(Identifiers.Injector))) {
return dep;
}
// access providers
- if (isPresent(this._getLocalProvider(requestingProviderType, dep.token, eager))) {
+ if (isPresent(this._getOrCreateLocalProvider(requestingProviderType, dep.token, eager))) {
return dep;
}
}
@@ -393,11 +421,11 @@ function _getContentQueries(
function _addQueryToTokenMap(map: CompileTokenMap,
query: CompileQueryMetadata) {
- query.selectors.forEach((selector) => {
- var entry = map.get(selector);
+ query.selectors.forEach((token: CompileTokenMetadata) => {
+ var entry = map.get(token);
if (isBlank(entry)) {
entry = [];
- map.add(selector, entry);
+ map.add(token, entry);
}
entry.push(query);
});
diff --git a/modules/angular2/src/compiler/runtime_compiler.ts b/modules/angular2/src/compiler/runtime_compiler.ts
index 299d29b82d..d7c98f3060 100644
--- a/modules/angular2/src/compiler/runtime_compiler.ts
+++ b/modules/angular2/src/compiler/runtime_compiler.ts
@@ -225,8 +225,8 @@ class CompiledTemplate {
viewFactory: Function = null;
proxyViewFactory: Function;
constructor() {
- this.proxyViewFactory = (viewManager, childInjector, contextEl) =>
- this.viewFactory(viewManager, childInjector, contextEl);
+ this.proxyViewFactory = (viewUtils, childInjector, contextEl) =>
+ this.viewFactory(viewUtils, childInjector, contextEl);
}
init(viewFactory: Function) { this.viewFactory = viewFactory; }
diff --git a/modules/angular2/src/compiler/runtime_metadata.ts b/modules/angular2/src/compiler/runtime_metadata.ts
index afecf4d46d..b066816736 100644
--- a/modules/angular2/src/compiler/runtime_metadata.ts
+++ b/modules/angular2/src/compiler/runtime_metadata.ts
@@ -295,7 +295,8 @@ export class RuntimeMetadataResolver {
selectors: selectors,
first: q.first,
descendants: q.descendants,
- propertyName: propertyName
+ propertyName: propertyName,
+ read: isPresent(q.read) ? this.getTokenMetadata(q.read) : null
});
}
}
diff --git a/modules/angular2/src/compiler/template_ast.ts b/modules/angular2/src/compiler/template_ast.ts
index d8c3f92899..558956010a 100644
--- a/modules/angular2/src/compiler/template_ast.ts
+++ b/modules/angular2/src/compiler/template_ast.ts
@@ -98,8 +98,9 @@ export class ElementAst implements TemplateAst {
constructor(public name: string, public attrs: AttrAst[],
public inputs: BoundElementPropertyAst[], public outputs: BoundEventAst[],
public exportAsVars: VariableAst[], public directives: DirectiveAst[],
- public providers: ProviderAst[], public children: TemplateAst[],
- public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
+ public providers: ProviderAst[], public hasViewContainer: boolean,
+ public children: TemplateAst[], public ngContentIndex: number,
+ public sourceSpan: ParseSourceSpan) {}
visit(visitor: TemplateAstVisitor, context: any): any {
return visitor.visitElement(this, context);
@@ -129,8 +130,8 @@ export class ElementAst implements TemplateAst {
export class EmbeddedTemplateAst implements TemplateAst {
constructor(public attrs: AttrAst[], public outputs: BoundEventAst[], public vars: VariableAst[],
public directives: DirectiveAst[], public providers: ProviderAst[],
- public children: TemplateAst[], public ngContentIndex: number,
- public sourceSpan: ParseSourceSpan) {}
+ public hasViewContainer: boolean, public children: TemplateAst[],
+ public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
visit(visitor: TemplateAstVisitor, context: any): any {
return visitor.visitEmbeddedTemplate(this, context);
diff --git a/modules/angular2/src/compiler/template_parser.ts b/modules/angular2/src/compiler/template_parser.ts
index 0595beedd0..407f0c50af 100644
--- a/modules/angular2/src/compiler/template_parser.ts
+++ b/modules/angular2/src/compiler/template_parser.ts
@@ -328,7 +328,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
var isViewRoot = parent.isTemplateElement || hasInlineTemplates;
var providerContext =
new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot,
- directiveAsts, attrs, element.sourceSpan);
+ directiveAsts, attrs, vars, element.sourceSpan);
var children = htmlVisitAll(
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
ElementContext.create(isTemplateElement, directiveAsts,
@@ -355,10 +355,10 @@ class TemplateParseVisitor implements HtmlAstVisitor {
this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps,
element.sourceSpan);
- parsedElement =
- new EmbeddedTemplateAst(attrs, events, vars, providerContext.transformedDirectiveAsts,
- providerContext.transformProviders, children,
- hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
+ parsedElement = new EmbeddedTemplateAst(
+ attrs, events, vars, providerContext.transformedDirectiveAsts,
+ providerContext.transformProviders, providerContext.transformedHasViewContainer, children,
+ hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
} else {
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
var elementExportAsVars = vars.filter(varAst => varAst.value.length === 0);
@@ -367,7 +367,8 @@ class TemplateParseVisitor implements HtmlAstVisitor {
parsedElement = new ElementAst(
nodeName, attrs, elementProps, events, elementExportAsVars,
- providerContext.transformedDirectiveAsts, providerContext.transformProviders, children,
+ providerContext.transformedDirectiveAsts, providerContext.transformProviders,
+ providerContext.transformedHasViewContainer, children,
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
}
if (hasInlineTemplates) {
@@ -382,12 +383,13 @@ class TemplateParseVisitor implements HtmlAstVisitor {
templateDirectiveAsts, templateElementProps, element.sourceSpan);
var templateProviderContext = new ProviderElementContext(
this.providerViewContext, parent.providerContext, parent.isTemplateElement,
- templateDirectiveAsts, [], element.sourceSpan);
+ templateDirectiveAsts, [], templateVars, element.sourceSpan);
templateProviderContext.afterElement();
parsedElement = new EmbeddedTemplateAst([], [], templateVars,
templateProviderContext.transformedDirectiveAsts,
templateProviderContext.transformProviders,
+ templateProviderContext.transformedHasViewContainer,
[parsedElement], ngContentIndex, element.sourceSpan);
}
return parsedElement;
@@ -765,8 +767,8 @@ class NonBindableVisitor implements HtmlAstVisitor {
var selector = createElementCssSelector(ast.name, attrNameAndValues);
var ngContentIndex = parent.findNgContentIndex(selector);
var children = htmlVisitAll(this, ast.children, EMPTY_ELEMENT_CONTEXT);
- return new ElementAst(ast.name, htmlVisitAll(this, ast.attrs), [], [], [], [], [], children,
- ngContentIndex, ast.sourceSpan);
+ return new ElementAst(ast.name, htmlVisitAll(this, ast.attrs), [], [], [], [], [], false,
+ children, ngContentIndex, ast.sourceSpan);
}
visitComment(ast: HtmlCommentAst, context: any): any { return null; }
visitAttr(ast: HtmlAttrAst, context: any): AttrAst {
diff --git a/modules/angular2/src/compiler/view_compiler/compile_element.ts b/modules/angular2/src/compiler/view_compiler/compile_element.ts
index c1f5ad32d5..6c5b0446d5 100644
--- a/modules/angular2/src/compiler/view_compiler/compile_element.ts
+++ b/modules/angular2/src/compiler/view_compiler/compile_element.ts
@@ -30,13 +30,13 @@ export class CompileNode {
export class CompileElement extends CompileNode {
static createNull(): CompileElement {
- return new CompileElement(null, null, null, null, null, [], [], {});
+ return new CompileElement(null, null, null, null, null, null, [], [], false, false, {});
}
private _compViewExpr: o.Expression = null;
- public component: CompileDirectiveMetadata = null;
- private _appElement: o.Expression;
- private _defaultInjector: o.Expression;
+ public appElement: o.ReadPropExpr;
+ public elementRef: o.Expression;
+ public injector: o.Expression;
private _instances = new CompileTokenMap();
private _resolvedProviders: CompileTokenMap;
@@ -50,17 +50,45 @@ export class CompileElement extends CompileNode {
constructor(parent: CompileElement, view: CompileView, nodeIndex: number,
renderNode: o.Expression, sourceAst: TemplateAst,
+ public component: CompileDirectiveMetadata,
private _directives: CompileDirectiveMetadata[],
- private _resolvedProvidersArray: ProviderAst[],
+ private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
+ public hasEmbeddedView: boolean,
public variableTokens: {[key: string]: CompileTokenMetadata}) {
super(parent, view, nodeIndex, renderNode, sourceAst);
+ this.elementRef = o.importExpr(Identifiers.ElementRef).instantiate([this.renderNode]);
+ this._instances.add(identifierToken(Identifiers.ElementRef), this.elementRef);
+ this.injector = o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]);
+ this._instances.add(identifierToken(Identifiers.Injector), this.injector);
+ this._instances.add(identifierToken(Identifiers.Renderer), o.THIS_EXPR.prop('renderer'));
+ if (this.hasViewContainer || this.hasEmbeddedView || isPresent(this.component)) {
+ this._createAppElement();
+ }
}
- setComponent(component: CompileDirectiveMetadata, compViewExpr: o.Expression) {
- this.component = component;
+ private _createAppElement() {
+ var fieldName = `_appEl_${this.nodeIndex}`;
+ var parentNodeIndex = this.isRootElement() ? null : this.parent.nodeIndex;
+ this.view.fields.push(new o.ClassField(fieldName, o.importType(Identifiers.AppElement),
+ [o.StmtModifier.Private]));
+ var statement = o.THIS_EXPR.prop(fieldName)
+ .set(o.importExpr(Identifiers.AppElement)
+ .instantiate([
+ o.literal(this.nodeIndex),
+ o.literal(parentNodeIndex),
+ o.THIS_EXPR,
+ this.renderNode
+ ]))
+ .toStmt();
+ this.view.createMethod.addStmt(statement);
+ this.appElement = o.THIS_EXPR.prop(fieldName);
+ this._instances.add(identifierToken(Identifiers.AppElement), this.appElement);
+ }
+
+ setComponentView(compViewExpr: o.Expression) {
this._compViewExpr = compViewExpr;
this.contentNodesByNgContentIndex =
- ListWrapper.createFixedSize(component.template.ngContentSelectors.length);
+ ListWrapper.createFixedSize(this.component.template.ngContentSelectors.length);
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
this.contentNodesByNgContentIndex[i] = [];
}
@@ -71,7 +99,7 @@ export class CompileElement extends CompileNode {
if (isPresent(embeddedView)) {
var createTemplateRefExpr =
o.importExpr(Identifiers.TemplateRef_)
- .instantiate([this.getOrCreateAppElement(), this.embeddedView.viewFactory]);
+ .instantiate([this.appElement, this.embeddedView.viewFactory]);
var provider = new CompileProviderMetadata(
{token: identifierToken(Identifiers.TemplateRef), useValue: createTemplateRefExpr});
// Add TemplateRef as first provider as it does not have deps on other providers
@@ -82,6 +110,11 @@ export class CompileElement extends CompileNode {
}
beforeChildren(): void {
+ if (this.hasViewContainer) {
+ this._instances.add(identifierToken(Identifiers.ViewContainerRef),
+ this.appElement.prop('vcRef'));
+ }
+
this._resolvedProviders = new CompileTokenMap();
this._resolvedProvidersArray.forEach(provider =>
this._resolvedProviders.add(provider.token, provider));
@@ -127,36 +160,54 @@ export class CompileElement extends CompileNode {
var directive = this._directives[i];
directive.queries.forEach((queryMeta) => { this._addQuery(queryMeta, directiveInstance); });
}
+ var queriesWithReads: _QueryWithRead[] = [];
this._resolvedProviders.values().forEach((resolvedProvider) => {
var queriesForProvider = this._getQueriesFor(resolvedProvider.token);
- var providerExpr = this._instances.get(resolvedProvider.token);
- queriesForProvider.forEach((query) => { query.addValue(providerExpr, this.view); });
+ ListWrapper.addAll(
+ queriesWithReads,
+ queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
});
StringMapWrapper.forEach(this.variableTokens, (_, varName) => {
var token = this.variableTokens[varName];
var varValue;
- var varValueForQuery;
if (isPresent(token)) {
- varValue = varValueForQuery = this._instances.get(token);
+ varValue = this._instances.get(token);
} else {
- varValueForQuery = this.getOrCreateAppElement().prop('ref');
varValue = this.renderNode;
}
this.view.variables.set(varName, varValue);
- this.view.namedAppElements.push([varName, this.getOrCreateAppElement()]);
-
- var queriesForProvider = this._getQueriesFor(new CompileTokenMetadata({value: varName}));
- queriesForProvider.forEach((query) => { query.addValue(varValueForQuery, this.view); });
+ var varToken = new CompileTokenMetadata({value: varName});
+ ListWrapper.addAll(queriesWithReads, this._getQueriesFor(varToken)
+ .map(query => new _QueryWithRead(query, varToken)));
});
+ queriesWithReads.forEach((queryWithRead) => {
+ var value: o.Expression;
+ if (isPresent(queryWithRead.read.identifier)) {
+ // query for an identifier
+ value = this._instances.get(queryWithRead.read);
+ } else {
+ // query for a variable
+ var token = this.variableTokens[queryWithRead.read.value];
+ if (isPresent(token)) {
+ value = this._instances.get(token);
+ } else {
+ value = this.elementRef;
+ }
+ }
+ if (isPresent(value)) {
+ queryWithRead.query.addValue(value, this.view);
+ }
+ });
+
if (isPresent(this.component)) {
var componentConstructorViewQueryList =
isPresent(this.component) ? o.literalArr(this._componentConstructorViewQueryLists) :
o.NULL_EXPR;
var compExpr = isPresent(this.getComponent()) ? this.getComponent() : o.NULL_EXPR;
this.view.createMethod.addStmt(
- this.getOrCreateAppElement()
- .callMethod('initComponent',
- [compExpr, componentConstructorViewQueryList, this._compViewExpr])
+ this.appElement.callMethod(
+ 'initComponent',
+ [compExpr, componentConstructorViewQueryList, this._compViewExpr])
.toStmt());
}
}
@@ -202,43 +253,6 @@ export class CompileElement extends CompileNode {
return res;
}
- getOptionalAppElement(): o.Expression { return this._appElement; }
-
- getOrCreateAppElement(): o.Expression {
- if (isBlank(this._appElement)) {
- var parentNodeIndex = this.isRootElement() ? null : this.parent.nodeIndex;
- var fieldName = `_appEl_${this.nodeIndex}`;
- this.view.fields.push(new o.ClassField(fieldName, o.importType(Identifiers.AppElement),
- [o.StmtModifier.Private]));
- var statement = o.THIS_EXPR.prop(fieldName)
- .set(o.importExpr(Identifiers.AppElement)
- .instantiate([
- o.literal(this.nodeIndex),
- o.literal(parentNodeIndex),
- o.THIS_EXPR,
- this.renderNode
- ]))
- .toStmt();
- this.view.createMethod.addStmt(statement);
- this._appElement = o.THIS_EXPR.prop(fieldName);
- }
- return this._appElement;
- }
-
- getOrCreateInjector(): o.Expression {
- if (isBlank(this._defaultInjector)) {
- var fieldName = `_inj_${this.nodeIndex}`;
- this.view.fields.push(new o.ClassField(fieldName, o.importType(Identifiers.Injector),
- [o.StmtModifier.Private]));
- var statement = o.THIS_EXPR.prop(fieldName)
- .set(o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]))
- .toStmt();
- this.view.createMethod.addStmt(statement);
- this._defaultInjector = o.THIS_EXPR.prop(fieldName);
- }
- return this._defaultInjector;
- }
-
private _getQueriesFor(token: CompileTokenMetadata): CompileQuery[] {
var result: CompileQuery[] = [];
var currentEl: CompileElement = this;
@@ -289,30 +303,20 @@ export class CompileElement extends CompileNode {
}
if (isPresent(dep.token)) {
- // access builtins
+ // access builtins with special visibility
if (isBlank(result)) {
- if (dep.token.equalsTo(identifierToken(Identifiers.Renderer))) {
- result = o.THIS_EXPR.prop('renderer');
- } else if (dep.token.equalsTo(identifierToken(Identifiers.ElementRef))) {
- result = this.getOrCreateAppElement().prop('ref');
- } else if (dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef))) {
+ if (dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef))) {
if (requestingProviderType === ProviderAstType.Component) {
return this._compViewExpr.prop('ref');
} else {
return o.THIS_EXPR.prop('ref');
}
- } else if (dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef))) {
- result = this.getOrCreateAppElement().prop('vcRef');
}
}
- // access providers
+ // access regular providers on the element
if (isBlank(result)) {
result = this._instances.get(dep.token);
}
- // access the injector
- if (isBlank(result) && dep.token.equalsTo(identifierToken(Identifiers.Injector))) {
- result = this.getOrCreateInjector();
- }
}
return result;
}
@@ -400,3 +404,10 @@ function createProviderProperty(propName: string, provider: ProviderAst,
}
return o.THIS_EXPR.prop(propName);
}
+
+class _QueryWithRead {
+ public read: CompileTokenMetadata;
+ constructor(public query: CompileQuery, match: CompileTokenMetadata) {
+ this.read = isPresent(query.meta.read) ? query.meta.read : match;
+ }
+}
diff --git a/modules/angular2/src/compiler/view_compiler/compile_query.ts b/modules/angular2/src/compiler/view_compiler/compile_query.ts
index 22f920d9d3..64c8b40c52 100644
--- a/modules/angular2/src/compiler/view_compiler/compile_query.ts
+++ b/modules/angular2/src/compiler/view_compiler/compile_query.ts
@@ -77,7 +77,7 @@ export class CompileQuery {
function createQueryValues(viewValues: ViewQueryValues): o.Expression[] {
return ListWrapper.flatten(viewValues.values.map((entry) => {
if (entry instanceof ViewQueryValues) {
- return mapNestedViews(entry.view.declarationElement.getOrCreateAppElement(), entry.view,
+ return mapNestedViews(entry.view.declarationElement.appElement, entry.view,
createQueryValues(entry));
} else {
return entry;
diff --git a/modules/angular2/src/compiler/view_compiler/compile_view.ts b/modules/angular2/src/compiler/view_compiler/compile_view.ts
index 36d3ad58be..9d7a8b22a2 100644
--- a/modules/angular2/src/compiler/view_compiler/compile_view.ts
+++ b/modules/angular2/src/compiler/view_compiler/compile_view.ts
@@ -33,9 +33,9 @@ export class CompilePipe {
export class CompileView implements NameResolver {
public viewType: ViewType;
public viewQueries: CompileTokenMap;
- public namedAppElements: Array> = [];
public nodes: CompileNode[] = [];
+ // root nodes or AppElements for ViewContainers
public rootNodesOrAppElements: o.Expression[] = [];
public bindings: CompileBinding[] = [];
diff --git a/modules/angular2/src/compiler/view_compiler/constants.ts b/modules/angular2/src/compiler/view_compiler/constants.ts
index 596fd7f095..3f752dbfc7 100644
--- a/modules/angular2/src/compiler/view_compiler/constants.ts
+++ b/modules/angular2/src/compiler/view_compiler/constants.ts
@@ -59,7 +59,7 @@ export class ChangeDetectionStrategyEnum {
}
export class ViewConstructorVars {
- static viewManager = o.variable('viewManager');
+ static viewUtils = o.variable('viewUtils');
static parentInjector = o.variable('parentInjector');
static declarationEl = o.variable('declarationEl');
}
@@ -67,7 +67,7 @@ export class ViewConstructorVars {
export class ViewProperties {
static renderer = o.THIS_EXPR.prop('renderer');
static projectableNodes = o.THIS_EXPR.prop('projectableNodes');
- static viewManager = o.THIS_EXPR.prop('viewManager');
+ static viewUtils = o.THIS_EXPR.prop('viewUtils');
}
export class EventHandlerVars { static event = o.variable('$event'); }
diff --git a/modules/angular2/src/compiler/view_compiler/event_binder.ts b/modules/angular2/src/compiler/view_compiler/event_binder.ts
index 3f59de70bf..dd04020467 100644
--- a/modules/angular2/src/compiler/view_compiler/event_binder.ts
+++ b/modules/angular2/src/compiler/view_compiler/event_binder.ts
@@ -67,10 +67,9 @@ export class CompileEventListener {
}
finishMethod() {
- var markPathToRootStart =
- this._hasComponentHostListener ?
- this.compileElement.getOrCreateAppElement().prop('componentView') :
- o.THIS_EXPR;
+ var markPathToRootStart = this._hasComponentHostListener ?
+ this.compileElement.appElement.prop('componentView') :
+ o.THIS_EXPR;
var resultExpr: o.Expression = o.literal(true);
this._actionResultExprs.forEach((expr) => { resultExpr = resultExpr.and(expr); });
var stmts =
diff --git a/modules/angular2/src/compiler/view_compiler/property_binder.ts b/modules/angular2/src/compiler/view_compiler/property_binder.ts
index 8184ee2853..9b1da586ed 100644
--- a/modules/angular2/src/compiler/view_compiler/property_binder.ts
+++ b/modules/angular2/src/compiler/view_compiler/property_binder.ts
@@ -189,8 +189,7 @@ export function bindDirectiveInputs(directiveAst: DirectiveAst, directiveInstanc
});
if (isOnPushComp) {
detectChangesInInputsMethod.addStmt(new o.IfStmt(DetectChangesVars.changed, [
- compileElement.getOrCreateAppElement()
- .prop('componentView')
+ compileElement.appElement.prop('componentView')
.callMethod('markAsCheckOnce', [])
.toStmt()
]));
diff --git a/modules/angular2/src/compiler/view_compiler/view_builder.ts b/modules/angular2/src/compiler/view_compiler/view_builder.ts
index 253a28f9c7..275591f77d 100644
--- a/modules/angular2/src/compiler/view_compiler/view_builder.ts
+++ b/modules/angular2/src/compiler/view_compiler/view_builder.ts
@@ -92,14 +92,15 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
private _addRootNodeAndProject(node: CompileNode, ngContentIndex: number,
parent: CompileElement) {
- var appEl = node instanceof CompileElement ? node.getOptionalAppElement() : null;
+ var vcAppEl =
+ (node instanceof CompileElement && node.hasViewContainer) ? node.appElement : null;
if (this._isRootNode(parent)) {
- // store root nodes only for embedded/host views
+ // store appElement as root node only for ViewContainers
if (this.view.viewType !== ViewType.COMPONENT) {
- this.view.rootNodesOrAppElements.push(isPresent(appEl) ? appEl : node.renderNode);
+ this.view.rootNodesOrAppElements.push(isPresent(vcAppEl) ? vcAppEl : node.renderNode);
}
} else if (isPresent(parent.component) && isPresent(ngContentIndex)) {
- parent.addContentNode(ngContentIndex, isPresent(appEl) ? appEl : node.renderNode);
+ parent.addContentNode(ngContentIndex, isPresent(vcAppEl) ? vcAppEl : node.renderNode);
}
}
@@ -196,7 +197,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderElement),
[o.StmtModifier.Private]));
- var createRenderNode = o.THIS_EXPR.prop(fieldName).set(createRenderNodeExpr).toStmt();
+ this.view.createMethod.addStmt(o.THIS_EXPR.prop(fieldName).set(createRenderNodeExpr).toStmt());
var renderNode = o.THIS_EXPR.prop(fieldName);
@@ -204,7 +205,6 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
var directives = ast.directives.map(directiveAst => directiveAst.directive);
var variables =
_readHtmlAndDirectiveVariables(ast.exportAsVars, ast.directives, this.view.viewType);
- this.view.createMethod.addStmt(createRenderNode);
var htmlAttrs = _readHtmlAttrs(ast.attrs);
var attrNameAndValues = _mergeHtmlAndDirectiveAttrs(htmlAttrs, directives);
for (var i = 0; i < attrNameAndValues.length; i++) {
@@ -216,8 +216,9 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
[renderNode, o.literal(attrName), o.literal(attrValue)])
.toStmt());
}
- var compileElement = new CompileElement(parent, this.view, nodeIndex, renderNode, ast,
- directives, ast.providers, variables);
+ var compileElement =
+ new CompileElement(parent, this.view, nodeIndex, renderNode, ast, component, directives,
+ ast.providers, ast.hasViewContainer, false, variables);
this.view.nodes.push(compileElement);
var compViewExpr: o.ReadVarExpr = null;
if (isPresent(component)) {
@@ -225,14 +226,14 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
new CompileIdentifierMetadata({name: getViewFactoryName(component, 0)});
this.targetDependencies.push(new ViewCompileDependency(component, nestedComponentIdentifier));
compViewExpr = o.variable(`compView_${nodeIndex}`);
+ compileElement.setComponentView(compViewExpr);
this.view.createMethod.addStmt(compViewExpr.set(o.importExpr(nestedComponentIdentifier)
.callFn([
- ViewProperties.viewManager,
- compileElement.getOrCreateInjector(),
- compileElement.getOrCreateAppElement()
+ ViewProperties.viewUtils,
+ compileElement.injector,
+ compileElement.appElement
]))
.toDeclStmt());
- compileElement.setComponent(component, compViewExpr);
}
compileElement.beforeChildren();
this._addRootNodeAndProject(compileElement, ast.ngContentIndex, parent);
@@ -259,24 +260,25 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderComment),
[o.StmtModifier.Private]));
- var createRenderNode = o.THIS_EXPR.prop(fieldName)
- .set(ViewProperties.renderer.callMethod(
- 'createTemplateAnchor',
- [
- this._getParentRenderNode(parent),
- this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast)
- ]))
- .toStmt();
+ this.view.createMethod.addStmt(
+ o.THIS_EXPR.prop(fieldName)
+ .set(ViewProperties.renderer.callMethod(
+ 'createTemplateAnchor',
+ [
+ this._getParentRenderNode(parent),
+ this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast)
+ ]))
+ .toStmt());
var renderNode = o.THIS_EXPR.prop(fieldName);
var templateVariableBindings = ast.vars.map(
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
var directives = ast.directives.map(directiveAst => directiveAst.directive);
- var compileElement = new CompileElement(parent, this.view, nodeIndex, renderNode, ast,
- directives, ast.providers, {});
+ var compileElement =
+ new CompileElement(parent, this.view, nodeIndex, renderNode, ast, null, directives,
+ ast.providers, ast.hasViewContainer, true, {});
this.view.nodes.push(compileElement);
- this.view.createMethod.addStmt(createRenderNode);
this.nestedViewCount++;
var embeddedView = new CompileView(
@@ -413,7 +415,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
var emptyTemplateVariableBindings =
view.templateVariableBindings.map((entry) => [entry[0], o.NULL_EXPR]);
var viewConstructorArgs = [
- new o.FnParam(ViewConstructorVars.viewManager.name, o.importType(Identifiers.AppViewManager_)),
+ new o.FnParam(ViewConstructorVars.viewUtils.name, o.importType(Identifiers.ViewUtils)),
new o.FnParam(ViewConstructorVars.parentInjector.name, o.importType(Identifiers.Injector)),
new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement))
];
@@ -423,7 +425,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
renderCompTypeVar,
ViewTypeEnum.fromValue(view.viewType),
o.literalMap(emptyTemplateVariableBindings),
- ViewConstructorVars.viewManager,
+ ViewConstructorVars.viewUtils,
ViewConstructorVars.parentInjector,
ViewConstructorVars.declarationEl,
ChangeDetectionStrategyEnum.fromValue(getChangeDetectionMode(view)),
@@ -462,7 +464,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
function createViewFactory(view: CompileView, viewClass: o.ClassStmt,
renderCompTypeVar: o.ReadVarExpr): o.Statement {
var viewFactoryArgs = [
- new o.FnParam(ViewConstructorVars.viewManager.name, o.importType(Identifiers.AppViewManager_)),
+ new o.FnParam(ViewConstructorVars.viewUtils.name, o.importType(Identifiers.ViewUtils)),
new o.FnParam(ViewConstructorVars.parentInjector.name, o.importType(Identifiers.Injector)),
new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement))
];
@@ -478,15 +480,16 @@ function createViewFactory(view: CompileView, viewClass: o.ClassStmt,
initRenderCompTypeStmts = [
new o.IfStmt(renderCompTypeVar.identical(o.NULL_EXPR),
[
- renderCompTypeVar.set(ViewConstructorVars.viewManager
- .callMethod('createRenderComponentType',
- [
- o.literal(templateUrlInfo),
- o.literal(
- view.component.template.ngContentSelectors.length),
- ViewEncapsulationEnum.fromValue(view.component.template.encapsulation),
- view.styles
- ]))
+ renderCompTypeVar.set(ViewConstructorVars
+ .viewUtils.callMethod('createRenderComponentType',
+ [
+ o.literal(templateUrlInfo),
+ o.literal(view.component
+ .template.ngContentSelectors.length),
+ ViewEncapsulationEnum
+ .fromValue(view.component.template.encapsulation),
+ view.styles
+ ]))
.toStmt()
])
];
@@ -513,7 +516,7 @@ function generateCreateMethod(view: CompileView): o.Statement[] {
}
var resultExpr: o.Expression;
if (view.viewType === ViewType.HOST) {
- resultExpr = (view.nodes[0]).getOrCreateAppElement();
+ resultExpr = (view.nodes[0]).appElement;
} else {
resultExpr = o.NULL_EXPR;
}
@@ -523,7 +526,6 @@ function generateCreateMethod(view: CompileView): o.Statement[] {
[
createFlatArray(view.rootNodesOrAppElements),
o.literalArr(view.nodes.map(node => node.renderNode)),
- o.literalMap(view.namedAppElements),
o.literalArr(view.disposables),
o.literalArr(view.subscriptions)
])
diff --git a/modules/angular2/src/core/application_common_providers.ts b/modules/angular2/src/core/application_common_providers.ts
index 0785bfaa23..df0f8b7711 100644
--- a/modules/angular2/src/core/application_common_providers.ts
+++ b/modules/angular2/src/core/application_common_providers.ts
@@ -11,8 +11,7 @@ import {
KeyValueDiffers,
defaultKeyValueDiffers
} from './change_detection/change_detection';
-import {AppViewManager} from './linker/view_manager';
-import {AppViewManager_} from "./linker/view_manager";
+import {ViewUtils} from "./linker/view_utils";
import {ComponentResolver} from './linker/component_resolver';
import {ReflectorComponentResolver} from "./linker/component_resolver";
import {DynamicComponentLoader} from './linker/dynamic_component_loader';
@@ -27,7 +26,7 @@ var __unused: Type; // avoid unused import when Type union types are erased
export const APPLICATION_COMMON_PROVIDERS: Array = CONST_EXPR([
new Provider(ComponentResolver, {useClass: ReflectorComponentResolver}),
APP_ID_RANDOM_PROVIDER,
- new Provider(AppViewManager, {useClass: AppViewManager_}),
+ ViewUtils,
new Provider(IterableDiffers, {useValue: defaultIterableDiffers}),
new Provider(KeyValueDiffers, {useValue: defaultKeyValueDiffers}),
new Provider(DynamicComponentLoader, {useClass: DynamicComponentLoader_})
diff --git a/modules/angular2/src/core/linker.ts b/modules/angular2/src/core/linker.ts
index dba50ae7bb..15b2fd4a96 100644
--- a/modules/angular2/src/core/linker.ts
+++ b/modules/angular2/src/core/linker.ts
@@ -1,6 +1,5 @@
// Public API for compiler
export {ComponentResolver} from './linker/component_resolver';
-export {AppViewManager} from './linker/view_manager';
export {QueryList} from './linker/query_list';
export {DynamicComponentLoader} from './linker/dynamic_component_loader';
export {ElementRef} from './linker/element_ref';
diff --git a/modules/angular2/src/core/linker/component_factory.ts b/modules/angular2/src/core/linker/component_factory.ts
index 1f2e37632a..d51521eedc 100644
--- a/modules/angular2/src/core/linker/component_factory.ts
+++ b/modules/angular2/src/core/linker/component_factory.ts
@@ -1,10 +1,10 @@
import {Injector} from 'angular2/src/core/di';
import {Type, CONST, isPresent, isBlank} from 'angular2/src/facade/lang';
import {unimplemented} from 'angular2/src/facade/exceptions';
-import {ElementRef, ElementRef_} from './element_ref';
+import {ElementRef} from './element_ref';
import {ViewRef, ViewRef_} from './view_ref';
import {AppElement} from './element';
-import {AppViewManager} from './view_manager';
+import {ViewUtils} from './view_utils';
import {ChangeDetectorRef} from '../change_detection/change_detection';
/**
@@ -38,7 +38,7 @@ export abstract class ComponentRef {
/**
* The {@link ChangeDetectorRef} of the Component instance.
*/
- get changeDetectorRef(): ChangeDetectorRef { return unimplemented(); };
+ get changeDetectorRef(): ChangeDetectorRef { return unimplemented(); }
/**
* The component type.
@@ -57,15 +57,15 @@ export abstract class ComponentRef {
}
export class ComponentRef_ extends ComponentRef {
- constructor(private _location: AppElement, private _componentType: Type) { super(); }
- get location(): ElementRef { return this._location.ref; }
- get injector(): Injector { return this._location.injector; }
- get instance(): any { return this._location.component; };
- get hostView(): ViewRef { return this._location.parentView.ref; };
+ constructor(private _hostElement: AppElement, private _componentType: Type) { super(); }
+ get location(): ElementRef { return this._hostElement.elementRef; }
+ get injector(): Injector { return this._hostElement.injector; }
+ get instance(): any { return this._hostElement.component; };
+ get hostView(): ViewRef { return this._hostElement.parentView.ref; };
get changeDetectorRef(): ChangeDetectorRef { return this.hostView; };
get componentType(): Type { return this._componentType; }
- destroy(): void { this._location.parentView.destroy(); }
+ destroy(): void { this._hostElement.parentView.destroy(); }
onDestroy(callback: Function): void { this.hostView.onDestroy(callback); }
}
@@ -81,12 +81,12 @@ export class ComponentFactory {
*/
create(injector: Injector, projectableNodes: any[][] = null,
rootSelectorOrNode: string | any = null): ComponentRef {
- var vm: AppViewManager = injector.get(AppViewManager);
+ var vu: ViewUtils = injector.get(ViewUtils);
if (isBlank(projectableNodes)) {
projectableNodes = [];
}
// Note: Host views don't need a declarationAppElement!
- var hostView = this._viewFactory(vm, injector, null);
+ var hostView = this._viewFactory(vu, injector, null);
var hostElement = hostView.create(projectableNodes, rootSelectorOrNode);
return new ComponentRef_(hostElement, this._componentType);
}
diff --git a/modules/angular2/src/core/linker/dynamic_component_loader.ts b/modules/angular2/src/core/linker/dynamic_component_loader.ts
index 6d048f1a8d..7713f18292 100644
--- a/modules/angular2/src/core/linker/dynamic_component_loader.ts
+++ b/modules/angular2/src/core/linker/dynamic_component_loader.ts
@@ -1,9 +1,8 @@
import {Key, Injector, ResolvedProvider, Provider, provide, Injectable} from 'angular2/src/core/di';
import {ComponentResolver} from './component_resolver';
import {isType, Type, stringify, isPresent} from 'angular2/src/facade/lang';
-import {AppViewManager} from 'angular2/src/core/linker/view_manager';
-import {ElementRef, ElementRef_} from './element_ref';
import {ComponentRef} from './component_factory';
+import {ViewContainerRef} from './view_container_ref';
/**
* Service for instantiating a Component and attaching it to a View at a specified location.
@@ -61,60 +60,9 @@ export abstract class DynamicComponentLoader {
abstract loadAsRoot(type: Type, overrideSelectorOrNode: string | any, injector: Injector,
onDispose?: () => void, projectableNodes?: any[][]): Promise;
- /**
- * Creates an instance of a Component and attaches it to a View Container located inside of the
- * Component View of another Component instance.
- *
- * The targeted Component Instance is specified via its `hostLocation` {@link ElementRef}. The
- * location within the Component View of this Component Instance is specified via `anchorName`
- * Template Variable Name.
- *
- * You can optionally provide `providers` to configure the {@link Injector} provisioned for this
- * Component Instance.
- *
- * Returns a promise for the {@link ComponentRef} representing the newly created Component.
- *
- * ### Example
- *
- * ```
- * @Component({
- * selector: 'child-component',
- * template: 'Child'
- * })
- * class ChildComponent {
- * }
- *
- * @Component({
- * selector: 'my-app',
- * template: 'Parent ()'
- * })
- * class MyApp {
- * constructor(dcl: DynamicComponentLoader, elementRef: ElementRef) {
- * dcl.loadIntoLocation(ChildComponent, elementRef, 'child');
- * }
- * }
- *
- * bootstrap(MyApp);
- * ```
- *
- * Resulting DOM:
- *
- * ```
- *
- * Parent (
- *
- * Child
- * )
- *
- * ```
- */
- abstract loadIntoLocation(type: Type, hostLocation: ElementRef, anchorName: string,
- providers?: ResolvedProvider[],
- projectableNodes?: any[][]): Promise;
-
/**
* Creates an instance of a Component and attaches it to the View Container found at the
- * `location` specified as {@link ElementRef}.
+ * `location` specified as {@link ViewContainerRef}.
*
* You can optionally provide `providers` to configure the {@link Injector} provisioned for this
* Component Instance.
@@ -137,8 +85,8 @@ export abstract class DynamicComponentLoader {
* template: 'Parent'
* })
* class MyApp {
- * constructor(dcl: DynamicComponentLoader, elementRef: ElementRef) {
- * dcl.loadNextToLocation(ChildComponent, elementRef);
+ * constructor(dcl: DynamicComponentLoader, viewContainerRef: ViewContainerRef) {
+ * dcl.loadNextToLocation(ChildComponent, viewContainerRef);
* }
* }
*
@@ -152,15 +100,14 @@ export abstract class DynamicComponentLoader {
* Child
* ```
*/
- abstract loadNextToLocation(type: Type, location: ElementRef, providers?: ResolvedProvider[],
+ abstract loadNextToLocation(type: Type, location: ViewContainerRef,
+ providers?: ResolvedProvider[],
projectableNodes?: any[][]): Promise;
}
@Injectable()
export class DynamicComponentLoader_ extends DynamicComponentLoader {
- constructor(private _compiler: ComponentResolver, private _viewManager: AppViewManager) {
- super();
- }
+ constructor(private _compiler: ComponentResolver) { super(); }
loadAsRoot(type: Type, overrideSelectorOrNode: string | any, injector: Injector,
onDispose?: () => void, projectableNodes?: any[][]): Promise {
@@ -175,20 +122,11 @@ export class DynamicComponentLoader_ extends DynamicComponentLoader {
});
}
- loadIntoLocation(type: Type, hostLocation: ElementRef, anchorName: string,
- providers: ResolvedProvider[] = null,
- projectableNodes: any[][] = null): Promise {
- return this.loadNextToLocation(
- type, this._viewManager.getNamedElementInComponentView(hostLocation, anchorName), providers,
- projectableNodes);
- }
-
- loadNextToLocation(type: Type, location: ElementRef, providers: ResolvedProvider[] = null,
+ loadNextToLocation(type: Type, location: ViewContainerRef, providers: ResolvedProvider[] = null,
projectableNodes: any[][] = null): Promise {
return this._compiler.resolveComponent(type).then(componentFactory => {
- var viewContainer = this._viewManager.getViewContainer(location);
- return viewContainer.createComponent(componentFactory, viewContainer.length, providers,
- projectableNodes);
+ return location.createComponent(componentFactory, location.length, providers,
+ projectableNodes);
});
}
}
diff --git a/modules/angular2/src/core/linker/element.ts b/modules/angular2/src/core/linker/element.ts
index acc3ccadb9..d940ac97a6 100644
--- a/modules/angular2/src/core/linker/element.ts
+++ b/modules/angular2/src/core/linker/element.ts
@@ -6,37 +6,30 @@ import {Injector} from 'angular2/src/core/di';
import {AppView} from './view';
import {ViewType} from './view_type';
-import {ElementRef_} from './element_ref';
+import {ElementRef} from './element_ref';
import {ViewContainerRef, ViewContainerRef_} from './view_container_ref';
import {QueryList} from './query_list';
+/**
+ * An AppElement is created for elements that have a ViewContainerRef,
+ * a nested component or a element to keep data around
+ * that is needed for later instantiations.
+ */
export class AppElement {
public nestedViews: AppView[] = null;
public componentView: AppView = null;
- private _ref: ElementRef_;
- private _vcRef: ViewContainerRef_;
public component: any;
public componentConstructorViewQueries: QueryList[];
constructor(public index: number, public parentIndex: number, public parentView: AppView,
public nativeElement: any) {}
- get ref(): ElementRef_ {
- if (isBlank(this._ref)) {
- this._ref = new ElementRef_(this);
- }
- return this._ref;
- }
+ get elementRef(): ElementRef { return new ElementRef(this.nativeElement); }
- get vcRef(): ViewContainerRef_ {
- if (isBlank(this._vcRef)) {
- this._vcRef = new ViewContainerRef_(this);
- }
- return this._vcRef;
- }
+ get vcRef(): ViewContainerRef_ { return new ViewContainerRef_(this); }
initComponent(component: any, componentConstructorViewQueries: QueryList[],
view: AppView) {
diff --git a/modules/angular2/src/core/linker/element_ref.ts b/modules/angular2/src/core/linker/element_ref.ts
index ff74a672a5..02e7421b5e 100644
--- a/modules/angular2/src/core/linker/element_ref.ts
+++ b/modules/angular2/src/core/linker/element_ref.ts
@@ -10,7 +10,7 @@ import {AppElement} from './element';
// Note: We don't expose things like `Injector`, `ViewContainer`, ... here,
// i.e. users have to ask for what they need. With that, we can build better analysis tools
// and could do better codegen in the future.
-export abstract class ElementRef {
+export class ElementRef {
/**
* The underlying native element or `null` if direct access to native elements is not supported
* (e.g. when the application runs in a web worker).
@@ -30,13 +30,7 @@ export abstract class ElementRef {
*
*
*/
- get nativeElement(): any { return unimplemented(); }
-}
-
-export class ElementRef_ implements ElementRef {
- constructor(private _element: AppElement) {}
-
- get internalElement(): AppElement { return this._element; }
-
- get nativeElement() { return this._element.nativeElement; }
+ public nativeElement: any;
+
+ constructor(nativeElement: any) { this.nativeElement = nativeElement; }
}
diff --git a/modules/angular2/src/core/linker/template_ref.ts b/modules/angular2/src/core/linker/template_ref.ts
index 731de03f46..cd055d93f0 100644
--- a/modules/angular2/src/core/linker/template_ref.ts
+++ b/modules/angular2/src/core/linker/template_ref.ts
@@ -1,4 +1,4 @@
-import {ElementRef, ElementRef_} from './element_ref';
+import {ElementRef} from './element_ref';
import {AppElement} from './element';
import {AppView} from './view';
import {EmbeddedViewRef} from './view_ref';
@@ -37,11 +37,11 @@ export class TemplateRef_ extends TemplateRef {
constructor(private _appElement: AppElement, private _viewFactory: Function) { super(); }
createEmbeddedView(): EmbeddedViewRef {
- var view: AppView = this._viewFactory(this._appElement.parentView.viewManager,
+ var view: AppView = this._viewFactory(this._appElement.parentView.viewUtils,
this._appElement.parentInjector, this._appElement);
view.create(null, null);
return view.ref;
}
- get elementRef(): ElementRef { return this._appElement.ref; }
+ get elementRef(): ElementRef { return this._appElement.elementRef; }
}
diff --git a/modules/angular2/src/core/linker/view.ts b/modules/angular2/src/core/linker/view.ts
index 1c0bfe854e..dd1001f531 100644
--- a/modules/angular2/src/core/linker/view.ts
+++ b/modules/angular2/src/core/linker/view.ts
@@ -27,9 +27,9 @@ import {ObservableWrapper} from 'angular2/src/facade/async';
import {Renderer, RootRenderer, RenderComponentType} from 'angular2/src/core/render/api';
import {ViewRef_} from './view_ref';
-import {AppViewManager_, AppViewManager} from './view_manager';
import {ViewType} from './view_type';
import {
+ ViewUtils,
flattenNestedViewRenderNodes,
ensureSlotCount,
arrayLooseIdentical,
@@ -65,7 +65,6 @@ export abstract class AppView {
allNodes: any[];
disposables: Function[];
subscriptions: any[];
- namedAppElements: {[key: string]: AppElement};
contentChildren: AppView[] = [];
viewChildren: AppView[] = [];
renderParent: AppView;
@@ -95,13 +94,13 @@ export abstract class AppView {
private _hasExternalHostElement: boolean;
constructor(public clazz: any, public componentType: RenderComponentType, public type: ViewType,
- public locals: {[key: string]: any}, public viewManager: AppViewManager_,
+ public locals: {[key: string]: any}, public viewUtils: ViewUtils,
public parentInjector: Injector, public declarationAppElement: AppElement,
public cdMode: ChangeDetectionStrategy, literalArrayCacheSize: number,
literalMapCacheSize: number, public staticNodeDebugInfos: StaticNodeDebugInfo[]) {
this.ref = new ViewRef_(this);
if (type === ViewType.COMPONENT || type === ViewType.HOST) {
- this.renderer = viewManager.renderComponent(componentType);
+ this.renderer = viewUtils.renderComponent(componentType);
} else {
this.renderer = declarationAppElement.parentView.renderer;
}
@@ -145,15 +144,15 @@ export abstract class AppView {
}
/**
- * Overwritten by implementations
+ * Overwritten by implementations.
+ * Returns the AppElement for the host element for ViewType.HOST.
*/
createInternal(rootSelectorOrNode: string | any): AppElement { return null; }
- init(rootNodesOrAppElements: any[], allNodes: any[], appElements: {[key: string]: AppElement},
- disposables: Function[], subscriptions: any[]) {
+ init(rootNodesOrAppElements: any[], allNodes: any[], disposables: Function[],
+ subscriptions: any[]) {
this.rootNodesOrAppElements = rootNodesOrAppElements;
this.allNodes = allNodes;
- this.namedAppElements = appElements;
this.disposables = disposables;
this.subscriptions = subscriptions;
if (this.type === ViewType.COMPONENT) {
diff --git a/modules/angular2/src/core/linker/view_container_ref.ts b/modules/angular2/src/core/linker/view_container_ref.ts
index fec19ee998..9a434f8d28 100644
--- a/modules/angular2/src/core/linker/view_container_ref.ts
+++ b/modules/angular2/src/core/linker/view_container_ref.ts
@@ -7,7 +7,7 @@ import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
import {AppElement} from './element';
-import {ElementRef, ElementRef_} from './element_ref';
+import {ElementRef} from './element_ref';
import {TemplateRef, TemplateRef_} from './template_ref';
import {EmbeddedViewRef, ViewRef, ViewRef_} from './view_ref';
import {ComponentFactory, ComponentRef} from './component_factory';
@@ -27,10 +27,7 @@ import {ComponentFactory, ComponentRef} from './component_factory';
* the Rendered View.
*
* To access a `ViewContainerRef` of an Element, you can either place a {@link Directive} injected
- * with `ViewContainerRef` on the Element, or you obtain it via
- * {@link AppViewManager#getViewContainer}.
- *
- *
+ * with `ViewContainerRef` on the Element, or you obtain it via a {@link ViewChild} query.
*/
export abstract class ViewContainerRef {
/**
@@ -121,7 +118,7 @@ export class ViewContainerRef_ implements ViewContainerRef {
return isPresent(views) ? views.length : 0;
}
- get element(): ElementRef { return this._element.ref; }
+ get element(): ElementRef { return this._element.elementRef; }
// TODO(rado): profile and decide whether bounds checks should be added
// to the methods below.
diff --git a/modules/angular2/src/core/linker/view_manager.ts b/modules/angular2/src/core/linker/view_manager.ts
deleted file mode 100644
index 3197049927..0000000000
--- a/modules/angular2/src/core/linker/view_manager.ts
+++ /dev/null
@@ -1,77 +0,0 @@
-import {
- Injector,
- Inject,
- Provider,
- Injectable,
- ResolvedProvider,
- forwardRef
-} from 'angular2/src/core/di';
-import {isPresent, isBlank, isArray, Type} from 'angular2/src/facade/lang';
-import {BaseException} from 'angular2/src/facade/exceptions';
-import {ElementRef, ElementRef_} from './element_ref';
-import {ViewContainerRef, ViewContainerRef_} from './view_container_ref';
-import {RootRenderer, RenderComponentType, Renderer} from 'angular2/src/core/render/api';
-import {APP_ID} from 'angular2/src/core/application_tokens';
-import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
-
-/**
- * Service exposing low level API for creating, moving and destroying Views.
- *
- * Most applications should use higher-level abstractions like {@link DynamicComponentLoader} and
- * {@link ViewContainerRef} instead.
- */
-export abstract class AppViewManager {
- /**
- * Returns a {@link ViewContainerRef} of the View Container at the specified location.
- */
- abstract getViewContainer(location: ElementRef): ViewContainerRef;
-
- /**
- * Searches the Component View of the Component specified via `hostLocation` and returns the
- * {@link ElementRef} for the Element identified via a Variable Name `variableName`.
- *
- * Throws an exception if the specified `hostLocation` is not a Host Element of a Component, or if
- * variable `variableName` couldn't be found in the Component View of this Component.
- */
- abstract getNamedElementInComponentView(hostLocation: ElementRef,
- variableName: string): ElementRef;
-}
-
-@Injectable()
-export class AppViewManager_ extends AppViewManager {
- private _nextCompTypeId: number = 0;
-
- constructor(private _renderer: RootRenderer, @Inject(APP_ID) private _appId: string) { super(); }
-
- getViewContainer(location: ElementRef): ViewContainerRef {
- return (location).internalElement.vcRef;
- }
-
- getNamedElementInComponentView(hostLocation: ElementRef, variableName: string): ElementRef {
- var appEl = (hostLocation).internalElement;
- var componentView = appEl.componentView;
- if (isBlank(componentView)) {
- throw new BaseException(`There is no component directive at element ${hostLocation}`);
- }
- var el = componentView.namedAppElements[variableName];
- if (isPresent(el)) {
- return el.ref;
- }
- throw new BaseException(`Could not find variable ${variableName}`);
- }
-
- /**
- * Used by the generated code
- */
- createRenderComponentType(templateUrl: string, slotCount: number,
- encapsulation: ViewEncapsulation,
- styles: Array): RenderComponentType {
- return new RenderComponentType(`${this._appId}-${this._nextCompTypeId++}`, templateUrl,
- slotCount, encapsulation, styles);
- }
-
- /** @internal */
- renderComponent(renderComponentType: RenderComponentType): Renderer {
- return this._renderer.renderComponent(renderComponentType);
- }
-}
diff --git a/modules/angular2/src/core/linker/view_utils.ts b/modules/angular2/src/core/linker/view_utils.ts
index f27dbb94b1..9f79e720e1 100644
--- a/modules/angular2/src/core/linker/view_utils.ts
+++ b/modules/angular2/src/core/linker/view_utils.ts
@@ -11,6 +11,32 @@ import {BaseException} from 'angular2/src/facade/exceptions';
import {AppElement} from './element';
import {ExpressionChangedAfterItHasBeenCheckedException} from './exceptions';
import {devModeEqual} from 'angular2/src/core/change_detection/change_detection';
+import {Inject, Injectable} from 'angular2/src/core/di';
+import {RootRenderer, RenderComponentType, Renderer} from 'angular2/src/core/render/api';
+import {APP_ID} from 'angular2/src/core/application_tokens';
+import {ViewEncapsulation} from 'angular2/src/core/metadata/view';
+
+@Injectable()
+export class ViewUtils {
+ private _nextCompTypeId: number = 0;
+
+ constructor(private _renderer: RootRenderer, @Inject(APP_ID) private _appId: string) {}
+
+ /**
+ * Used by the generated code
+ */
+ createRenderComponentType(templateUrl: string, slotCount: number,
+ encapsulation: ViewEncapsulation,
+ styles: Array): RenderComponentType {
+ return new RenderComponentType(`${this._appId}-${this._nextCompTypeId++}`, templateUrl,
+ slotCount, encapsulation, styles);
+ }
+
+ /** @internal */
+ renderComponent(renderComponentType: RenderComponentType): Renderer {
+ return this._renderer.renderComponent(renderComponentType);
+ }
+}
export function flattenNestedViewRenderNodes(nodes: any[]): any[] {
return _flattenNestedViewRenderNodes(nodes, []);
diff --git a/modules/angular2/src/core/metadata.dart b/modules/angular2/src/core/metadata.dart
index f4ea983677..fe0c8b9a57 100644
--- a/modules/angular2/src/core/metadata.dart
+++ b/modules/angular2/src/core/metadata.dart
@@ -145,8 +145,9 @@ class Attribute extends AttributeMetadata {
*/
@Deprecated("Use ContentChildren/ContentChild instead")
class Query extends QueryMetadata {
- const Query(dynamic /*Type | string*/ selector, {bool descendants: false})
- : super(selector, descendants: descendants);
+ const Query(dynamic /*Type | string*/ selector,
+ {bool descendants: false, dynamic read: null})
+ : super(selector, descendants: descendants, read: read);
}
/**
@@ -154,15 +155,15 @@ class Query extends QueryMetadata {
*/
class ContentChildren extends ContentChildrenMetadata {
const ContentChildren(dynamic /*Type | string*/ selector,
- {bool descendants: false})
- : super(selector, descendants: descendants);
+ {bool descendants: false, dynamic read: null})
+ : super(selector, descendants: descendants, read: read);
}
/**
* See: [ContentChildMetadata] for docs.
*/
class ContentChild extends ContentChildMetadata {
- const ContentChild(dynamic /*Type | string*/ selector) : super(selector);
+ const ContentChild(dynamic /*Type | string*/ selector, {dynamic read: null}) : super(selector, read: read);
}
/**
@@ -170,22 +171,22 @@ class ContentChild extends ContentChildMetadata {
*/
@Deprecated("Use ViewChildren/ViewChild instead")
class ViewQuery extends ViewQueryMetadata {
- const ViewQuery(dynamic /*Type | string*/ selector)
- : super(selector, descendants: true);
+ const ViewQuery(dynamic /*Type | string*/ selector, {dynamic read: null})
+ : super(selector, descendants: true, read: read);
}
/**
* See: [ViewChildrenMetadata] for docs.
*/
class ViewChildren extends ViewChildrenMetadata {
- const ViewChildren(dynamic /*Type | string*/ selector) : super(selector);
+ const ViewChildren(dynamic /*Type | string*/ selector, {dynamic read: null}) : super(selector, read: read);
}
/**
* See: [ViewChildMetadata] for docs.
*/
class ViewChild extends ViewChildMetadata {
- const ViewChild(dynamic /*Type | string*/ selector) : super(selector);
+ const ViewChild(dynamic /*Type | string*/ selector, {dynamic read: null}) : super(selector, read: read);
}
/**
diff --git a/modules/angular2/src/core/metadata.ts b/modules/angular2/src/core/metadata.ts
index a33e6b816f..8ae2184038 100644
--- a/modules/angular2/src/core/metadata.ts
+++ b/modules/angular2/src/core/metadata.ts
@@ -402,40 +402,43 @@ export interface AttributeMetadataFactory {
* ```
*/
export interface QueryMetadataFactory {
- (selector: Type | string, {descendants}?: {descendants?: boolean}): ParameterDecorator;
- new (selector: Type | string, {descendants}?: {descendants?: boolean}): QueryMetadata;
+ (selector: Type | string,
+ {descendants, read}?: {descendants?: boolean, read?: any}): ParameterDecorator;
+ new (selector: Type | string,
+ {descendants, read}?: {descendants?: boolean, read?: any}): QueryMetadata;
}
/**
* Factory for {@link ContentChildren}.
*/
export interface ContentChildrenMetadataFactory {
- (selector: Type | string, {descendants}?: {descendants?: boolean}): any;
- new (selector: Type | string, {descendants}?: {descendants?: boolean}): ContentChildrenMetadata;
+ (selector: Type | string, {descendants, read}?: {descendants?: boolean, read?: any}): any;
+ new (selector: Type | string,
+ {descendants, read}?: {descendants?: boolean, read?: any}): ContentChildrenMetadata;
}
/**
* Factory for {@link ContentChild}.
*/
export interface ContentChildMetadataFactory {
- (selector: Type | string): any;
- new (selector: Type | string): ContentChildMetadataFactory;
+ (selector: Type | string, {read}?: {read?: any}): any;
+ new (selector: Type | string, {read}?: {read?: any}): ContentChildMetadataFactory;
}
/**
* Factory for {@link ViewChildren}.
*/
export interface ViewChildrenMetadataFactory {
- (selector: Type | string): any;
- new (selector: Type | string): ViewChildrenMetadata;
+ (selector: Type | string, {read}?: {read?: any}): any;
+ new (selector: Type | string, {read}?: {read?: any}): ViewChildrenMetadata;
}
/**
* Factory for {@link ViewChild}.
*/
export interface ViewChildMetadataFactory {
- (selector: Type | string): any;
- new (selector: Type | string): ViewChildMetadataFactory;
+ (selector: Type | string, {read}?: {read?: any}): any;
+ new (selector: Type | string, {read}?: {read?: any}): ViewChildMetadataFactory;
}
diff --git a/modules/angular2/src/core/metadata/di.ts b/modules/angular2/src/core/metadata/di.ts
index 69c34a0b1a..d502dcc05e 100644
--- a/modules/angular2/src/core/metadata/di.ts
+++ b/modules/angular2/src/core/metadata/di.ts
@@ -149,12 +149,18 @@ export class QueryMetadata extends DependencyMetadata {
*/
descendants: boolean;
first: boolean;
+ /**
+ * The DI token to read from an element that matches the selector.
+ */
+ read: any;
constructor(private _selector: Type | string,
- {descendants = false, first = false}: {descendants?: boolean, first?: boolean} = {}) {
+ {descendants = false, first = false,
+ read = null}: {descendants?: boolean, first?: boolean, read?: any} = {}) {
super();
this.descendants = descendants;
this.first = first;
+ this.read = read;
}
/**
@@ -204,8 +210,9 @@ export class QueryMetadata extends DependencyMetadata {
*/
@CONST()
export class ContentChildrenMetadata extends QueryMetadata {
- constructor(_selector: Type | string, {descendants = false}: {descendants?: boolean} = {}) {
- super(_selector, {descendants: descendants});
+ constructor(_selector: Type | string,
+ {descendants = false, read = null}: {descendants?: boolean, read?: any} = {}) {
+ super(_selector, {descendants: descendants, read: read});
}
}
@@ -232,7 +239,9 @@ export class ContentChildrenMetadata extends QueryMetadata {
*/
@CONST()
export class ContentChildMetadata extends QueryMetadata {
- constructor(_selector: Type | string) { super(_selector, {descendants: true, first: true}); }
+ constructor(_selector: Type | string, {read = null}: {read?: any} = {}) {
+ super(_selector, {descendants: true, first: true, read: read});
+ }
}
/**
@@ -273,8 +282,9 @@ export class ContentChildMetadata extends QueryMetadata {
@CONST()
export class ViewQueryMetadata extends QueryMetadata {
constructor(_selector: Type | string,
- {descendants = false, first = false}: {descendants?: boolean, first?: boolean} = {}) {
- super(_selector, {descendants: descendants, first: first});
+ {descendants = false, first = false,
+ read = null}: {descendants?: boolean, first?: boolean, read?: any} = {}) {
+ super(_selector, {descendants: descendants, first: first, read: read});
}
/**
@@ -363,7 +373,9 @@ export class ViewQueryMetadata extends QueryMetadata {
*/
@CONST()
export class ViewChildrenMetadata extends ViewQueryMetadata {
- constructor(_selector: Type | string) { super(_selector, {descendants: true}); }
+ constructor(_selector: Type | string, {read = null}: {read?: any} = {}) {
+ super(_selector, {descendants: true, read: read});
+ }
}
/**
@@ -438,5 +450,7 @@ export class ViewChildrenMetadata extends ViewQueryMetadata {
*/
@CONST()
export class ViewChildMetadata extends ViewQueryMetadata {
- constructor(_selector: Type | string) { super(_selector, {descendants: true, first: true}); }
+ constructor(_selector: Type | string, {read = null}: {read?: any} = {}) {
+ super(_selector, {descendants: true, first: true, read: read});
+ }
}
diff --git a/modules/angular2/src/router/directives/router_link_transform.ts b/modules/angular2/src/router/directives/router_link_transform.ts
index 8f0aa3e4c4..f6ea5a01f7 100644
--- a/modules/angular2/src/router/directives/router_link_transform.ts
+++ b/modules/angular2/src/router/directives/router_link_transform.ts
@@ -186,8 +186,8 @@ export class RouterLinkTransform implements TemplateAstVisitor {
let updatedInputs = ast.inputs.map(c => c.visit(this, context));
let updatedDirectives = ast.directives.map(c => c.visit(this, context));
return new ElementAst(ast.name, ast.attrs, updatedInputs, ast.outputs, ast.exportAsVars,
- updatedDirectives, ast.providers, updatedChildren, ast.ngContentIndex,
- ast.sourceSpan);
+ updatedDirectives, ast.providers, ast.hasViewContainer, updatedChildren,
+ ast.ngContentIndex, ast.sourceSpan);
}
visitVariable(ast: any, context: any): any { return ast; }
diff --git a/modules/angular2/src/router/directives/router_outlet.ts b/modules/angular2/src/router/directives/router_outlet.ts
index f17248888f..7a72c3c761 100644
--- a/modules/angular2/src/router/directives/router_outlet.ts
+++ b/modules/angular2/src/router/directives/router_outlet.ts
@@ -7,7 +7,7 @@ import {
Attribute,
DynamicComponentLoader,
ComponentRef,
- ElementRef,
+ ViewContainerRef,
Injector,
provide,
Dependency,
@@ -40,7 +40,7 @@ export class RouterOutlet implements OnDestroy {
@Output('activate') public activateEvents = new EventEmitter();
- constructor(private _elementRef: ElementRef, private _loader: DynamicComponentLoader,
+ constructor(private _viewContainerRef: ViewContainerRef, private _loader: DynamicComponentLoader,
private _parentRouter: routerMod.Router, @Attribute('name') nameAttr: string) {
if (isPresent(nameAttr)) {
this.name = nameAttr;
@@ -66,7 +66,7 @@ export class RouterOutlet implements OnDestroy {
provide(routerMod.Router, {useValue: childRouter})
]);
this._componentRef =
- this._loader.loadNextToLocation(componentType, this._elementRef, providers);
+ this._loader.loadNextToLocation(componentType, this._viewContainerRef, providers);
return this._componentRef.then((componentRef) => {
this.activateEvents.emit(componentRef.instance);
if (hasLifecycleHook(hookMod.routerOnActivate, componentType)) {
diff --git a/modules/angular2/src/upgrade/constants.ts b/modules/angular2/src/upgrade/constants.ts
index 2c386ce826..7dcb8ecceb 100644
--- a/modules/angular2/src/upgrade/constants.ts
+++ b/modules/angular2/src/upgrade/constants.ts
@@ -1,4 +1,3 @@
-export const NG2_APP_VIEW_MANAGER = 'ng2.AppViewManager';
export const NG2_COMPILER = 'ng2.Compiler';
export const NG2_INJECTOR = 'ng2.Injector';
export const NG2_COMPONENT_FACTORY_REF_MAP = 'ng2.ComponentFactoryRefMap';
diff --git a/modules/angular2/src/upgrade/downgrade_ng2_adapter.ts b/modules/angular2/src/upgrade/downgrade_ng2_adapter.ts
index d4de559bf3..447d72c00b 100644
--- a/modules/angular2/src/upgrade/downgrade_ng2_adapter.ts
+++ b/modules/angular2/src/upgrade/downgrade_ng2_adapter.ts
@@ -1,6 +1,5 @@
import {
provide,
- AppViewManager,
ChangeDetectorRef,
Injector,
OnChanges,
@@ -30,8 +29,7 @@ export class DowngradeNg2ComponentAdapter {
constructor(private id: string, private info: ComponentInfo,
private element: angular.IAugmentedJQuery, private attrs: angular.IAttributes,
private scope: angular.IScope, private parentInjector: Injector,
- private parse: angular.IParseService, private viewManager: AppViewManager,
- private componentFactory: ComponentFactory) {
+ private parse: angular.IParseService, private componentFactory: ComponentFactory) {
(this.element[0]).id = id;
this.componentScope = scope.$new();
this.childNodes = element.contents();
diff --git a/modules/angular2/src/upgrade/upgrade_adapter.ts b/modules/angular2/src/upgrade/upgrade_adapter.ts
index 3b4d46876d..ecefdea1c3 100644
--- a/modules/angular2/src/upgrade/upgrade_adapter.ts
+++ b/modules/angular2/src/upgrade/upgrade_adapter.ts
@@ -2,7 +2,6 @@ import {
provide,
platform,
ApplicationRef,
- AppViewManager,
ComponentResolver,
Injector,
NgZone,
@@ -26,7 +25,6 @@ import {
NG1_ROOT_SCOPE,
NG1_SCOPE,
NG1_TESTABILITY,
- NG2_APP_VIEW_MANAGER,
NG2_COMPILER,
NG2_INJECTOR,
NG2_COMPONENT_FACTORY_REF_MAP,
@@ -318,7 +316,6 @@ export class UpgradeAdapter {
.value(NG2_ZONE, ngZone)
.value(NG2_COMPILER, compiler)
.value(NG2_COMPONENT_FACTORY_REF_MAP, componentFactoryRefMap)
- .value(NG2_APP_VIEW_MANAGER, injector.get(AppViewManager))
.config([
'$provide',
(provide) => {
@@ -542,10 +539,8 @@ interface ComponentFactoryRefMap {
}
function ng1ComponentDirective(info: ComponentInfo, idPrefix: string): Function {
- (directiveFactory).$inject =
- [NG2_COMPONENT_FACTORY_REF_MAP, NG2_APP_VIEW_MANAGER, NG1_PARSE];
+ (directiveFactory).$inject = [NG2_COMPONENT_FACTORY_REF_MAP, NG1_PARSE];
function directiveFactory(componentFactoryRefMap: ComponentFactoryRefMap,
- viewManager: AppViewManager,
parse: angular.IParseService): angular.IDirective {
var componentFactory: ComponentFactory = componentFactoryRefMap[info.selector];
if (!componentFactory) throw new Error('Expecting ComponentFactory for: ' + info.selector);
@@ -557,9 +552,9 @@ function ng1ComponentDirective(info: ComponentInfo, idPrefix: string): Function
post: (scope: angular.IScope, element: angular.IAugmentedJQuery, attrs: angular.IAttributes,
parentInjector: any, transclude: angular.ITranscludeFunction): void => {
var domElement = element[0];
- var facade = new DowngradeNg2ComponentAdapter(idPrefix + (idCount++), info, element,
- attrs, scope, parentInjector,
- parse, viewManager, componentFactory);
+ var facade =
+ new DowngradeNg2ComponentAdapter(idPrefix + (idCount++), info, element, attrs, scope,
+ parentInjector, parse, componentFactory);
facade.setupInputs();
facade.bootstrapNg2();
facade.projectContent();
diff --git a/modules/angular2/test/compiler/template_parser_spec.ts b/modules/angular2/test/compiler/template_parser_spec.ts
index 4ccb59c621..df266448bb 100644
--- a/modules/angular2/test/compiler/template_parser_spec.ts
+++ b/modules/angular2/test/compiler/template_parser_spec.ts
@@ -1506,7 +1506,8 @@ class FooAstTransformer implements TemplateAstVisitor {
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { throw 'not implemented'; }
visitElement(ast: ElementAst, context: any): any {
if (ast.name != 'div') return ast;
- return new ElementAst('foo', [], [], [], [], [], [], [], ast.ngContentIndex, ast.sourceSpan);
+ return new ElementAst('foo', [], [], [], [], [], [], false, [], ast.ngContentIndex,
+ ast.sourceSpan);
}
visitVariable(ast: VariableAst, context: any): any { throw 'not implemented'; }
visitEvent(ast: BoundEventAst, context: any): any { throw 'not implemented'; }
@@ -1523,6 +1524,7 @@ class FooAstTransformer implements TemplateAstVisitor {
class BarAstTransformer extends FooAstTransformer {
visitElement(ast: ElementAst, context: any): any {
if (ast.name != 'foo') return ast;
- return new ElementAst('bar', [], [], [], [], [], [], [], ast.ngContentIndex, ast.sourceSpan);
+ return new ElementAst('bar', [], [], [], [], [], [], false, [], ast.ngContentIndex,
+ ast.sourceSpan);
}
}
diff --git a/modules/angular2/test/core/linker/dynamic_component_loader_spec.ts b/modules/angular2/test/core/linker/dynamic_component_loader_spec.ts
index 3d94de6297..62ec28ce71 100644
--- a/modules/angular2/test/core/linker/dynamic_component_loader_spec.ts
+++ b/modules/angular2/test/core/linker/dynamic_component_loader_spec.ts
@@ -17,11 +17,11 @@ import {
} from 'angular2/testing_internal';
import {Predicate} from 'angular2/src/facade/collection';
-import {Injector, OnDestroy, DebugElement, Type} from 'angular2/core';
+import {Injector, OnDestroy, DebugElement, Type, ViewContainerRef, ViewChild} from 'angular2/core';
import {NgIf} from 'angular2/common';
import {Component, ViewMetadata} from 'angular2/src/core/metadata';
import {DynamicComponentLoader} from 'angular2/src/core/linker/dynamic_component_loader';
-import {ElementRef, ElementRef_} from 'angular2/src/core/linker/element_ref';
+import {ElementRef} from 'angular2/src/core/linker/element_ref';
import {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {BaseException} from 'angular2/src/facade/exceptions';
@@ -29,266 +29,112 @@ import {PromiseWrapper} from 'angular2/src/facade/promise';
export function main() {
describe('DynamicComponentLoader', function() {
- describe("loading into a location", () => {
+ describe("loading next to a location", () => {
it('should work',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(
- MyComp,
- new ViewMetadata(
- {template: '', directives: [Location]}))
- .createAsync(MyComp)
- .then((tc) => {
- loader.loadIntoLocation(DynamicallyLoaded, tc.elementRef, 'loc')
- .then(ref => {
- expect(tc.debugElement.nativeElement)
- .toHaveText("Location;DynamicallyLoaded;");
- async.done();
- });
- });
+ tcb.createAsync(MyComp).then((tc) => {
+ tc.detectChanges();
+ loader.loadNextToLocation(DynamicallyLoaded,
+ tc.componentInstance.viewContainerRef)
+ .then(ref => {
+ expect(tc.debugElement.nativeElement).toHaveText('DynamicallyLoaded;');
+
+ async.done();
+ });
+ });
}));
it('should return a disposable component ref',
- inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
- (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(
- MyComp,
- new ViewMetadata(
- {template: '', directives: [Location]}))
- .createAsync(MyComp)
- .then((tc) => {
-
- loader.loadIntoLocation(DynamicallyLoaded, tc.elementRef, 'loc')
- .then(ref => {
- ref.destroy();
- expect(tc.debugElement.nativeElement).toHaveText("Location;");
- async.done();
- });
- });
- }));
-
- it('should allow to destroy even if the location has been removed',
- inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
- (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(MyComp, new ViewMetadata({
- template: '',
- directives: [NgIf, ChildComp]
- }))
- .overrideView(
- ChildComp,
- new ViewMetadata(
- {template: '', directives: [Location]}))
- .createAsync(MyComp)
- .then((tc) => {
- tc.debugElement.componentInstance.ctxBoolProp = true;
- tc.detectChanges();
- var childElementRef = tc.debugElement.query(filterByDirective(ChildComp))
- .inject(ChildComp)
- .elementRef;
- loader.loadIntoLocation(DynamicallyLoaded, childElementRef, 'loc')
- .then(ref => {
- expect(tc.debugElement.nativeElement)
- .toHaveText("Location;DynamicallyLoaded;");
-
- tc.debugElement.componentInstance.ctxBoolProp = false;
- tc.detectChanges();
- expect(tc.debugElement.nativeElement).toHaveText("");
-
- ref.destroy();
- expect(tc.debugElement.nativeElement).toHaveText("");
- async.done();
- });
- });
- }));
-
- it('should update host properties',
inject(
[DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(
- MyComp, new ViewMetadata(
- {template: '', directives: [Location]}))
- .createAsync(MyComp)
- .then((tc) => {
- loader.loadIntoLocation(DynamicallyLoadedWithHostProps, tc.elementRef, 'loc')
- .then(ref => {
- ref.instance.id = "new value";
+ tcb.createAsync(MyComp).then((tc) => {
+ tc.detectChanges();
+ loader.loadNextToLocation(DynamicallyLoaded, tc.componentInstance.viewContainerRef)
+ .then(ref => {
+ loader.loadNextToLocation(DynamicallyLoaded2,
+ tc.componentInstance.viewContainerRef)
+ .then(ref2 => {
+ expect(tc.debugElement.nativeElement)
+ .toHaveText("DynamicallyLoaded;DynamicallyLoaded2;");
- tc.detectChanges();
+ ref2.destroy();
- var newlyInsertedElement =
- DOM.childNodes(tc.debugElement.nativeElement)[1];
- expect((newlyInsertedElement).id).toEqual("new value");
- async.done();
- });
- });
+ expect(tc.debugElement.nativeElement).toHaveText("DynamicallyLoaded;");
+
+ async.done();
+ });
+ });
+ });
}));
+ it('should update host properties',
+ inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
+ (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
+ tcb.createAsync(MyComp).then((tc) => {
+ tc.detectChanges();
+
+ loader.loadNextToLocation(DynamicallyLoadedWithHostProps,
+ tc.componentInstance.viewContainerRef)
+ .then(ref => {
+ ref.instance.id = "new value";
+
+ tc.detectChanges();
+
+ var newlyInsertedElement = tc.debugElement.childNodes[1].nativeNode;
+ expect((newlyInsertedElement).id).toEqual("new value");
+
+ async.done();
+ });
+ });
+ }));
+
+
+
it('should leave the view tree in a consistent state if hydration fails',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(MyComp, new ViewMetadata({
- template: '
',
- directives: [Location]
- }))
- .createAsync(MyComp)
- .then((tc: ComponentFixture) => {
- PromiseWrapper.catchError(
- loader.loadIntoLocation(DynamicallyLoadedThrows, tc.elementRef, 'loc'),
- (error) => {
- expect(error.message).toContain("ThrownInConstructor");
- expect(() => tc.detectChanges()).not.toThrow();
- async.done();
- return null;
- });
- });
- }));
-
- it('should throw if the variable does not exist',
- inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
- (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(
- MyComp,
- new ViewMetadata(
- {template: '', directives: [Location]}))
- .createAsync(MyComp)
- .then((tc) => {
- expect(() => loader.loadIntoLocation(DynamicallyLoadedWithHostProps,
- tc.elementRef, 'someUnknownVariable'))
- .toThrowError('Could not find variable someUnknownVariable');
- async.done();
- });
+ tcb.createAsync(MyComp).then((tc: ComponentFixture) => {
+ tc.detectChanges();
+ PromiseWrapper.catchError(
+ loader.loadNextToLocation(DynamicallyLoadedThrows,
+ tc.componentInstance.viewContainerRef),
+ (error) => {
+ expect(error.message).toContain("ThrownInConstructor");
+ expect(() => tc.detectChanges()).not.toThrow();
+ async.done();
+ return null;
+ });
+ });
}));
it('should allow to pass projectable nodes',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(MyComp,
- new ViewMetadata({template: '', directives: []}))
- .createAsync(MyComp)
- .then((tc) => {
- loader.loadIntoLocation(DynamicallyLoadedWithNgContent, tc.elementRef,
- 'loc', null, [[DOM.createTextNode('hello')]])
- .then(ref => {
- tc.detectChanges();
- expect(tc.nativeElement).toHaveText('dynamic(hello)');
- async.done();
- });
- });
+ tcb.createAsync(MyComp).then((tc) => {
+ tc.detectChanges();
+ loader.loadNextToLocation(DynamicallyLoadedWithNgContent,
+ tc.componentInstance.viewContainerRef, null,
+ [[DOM.createTextNode('hello')]])
+ .then(ref => {
+ tc.detectChanges();
+ var newlyInsertedElement = tc.debugElement.childNodes[1].nativeNode;
+ expect(newlyInsertedElement).toHaveText('dynamic(hello)');
+ async.done();
+ });
+ });
}));
it('should not throw if not enough projectable nodes are passed in',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(MyComp,
- new ViewMetadata({template: '', directives: []}))
- .createAsync(MyComp)
- .then((tc) => {
- loader.loadIntoLocation(DynamicallyLoadedWithNgContent, tc.elementRef,
- 'loc', null, [])
- .then((_) => { async.done(); });
- });
- }));
-
- });
-
- describe("loading next to a location", () => {
- it('should work',
- inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
- (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(MyComp, new ViewMetadata({
- template: '
',
- directives: [Location]
- }))
- .createAsync(MyComp)
- .then((tc) => {
- loader.loadNextToLocation(DynamicallyLoaded, tc.elementRef)
- .then(ref => {
- expect(tc.debugElement.nativeElement).toHaveText("Location;");
- expect(DOM.nextSibling(tc.debugElement.nativeElement))
- .toHaveText('DynamicallyLoaded;');
-
- async.done();
- });
- });
- }));
-
- it('should return a disposable component ref',
- inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
- (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(MyComp, new ViewMetadata({
- template: '
',
- directives: [Location]
- }))
- .
-
- createAsync(MyComp)
- .then((tc) => {
- loader.loadNextToLocation(DynamicallyLoaded, tc.elementRef)
- .then(ref => {
- loader.loadNextToLocation(DynamicallyLoaded2, tc.elementRef)
- .then(ref2 => {
- var firstSibling =
- DOM.nextSibling(tc.debugElement.nativeElement);
- var secondSibling = DOM.nextSibling(firstSibling);
- expect(tc.debugElement.nativeElement).toHaveText("Location;");
- expect(firstSibling).toHaveText("DynamicallyLoaded;");
- expect(secondSibling).toHaveText("DynamicallyLoaded2;");
-
- ref2.destroy();
-
- firstSibling = DOM.nextSibling(tc.debugElement.nativeElement);
- secondSibling = DOM.nextSibling(firstSibling);
- expect(secondSibling).toBeNull();
-
- async.done();
- });
- });
- });
- }));
-
- it('should update host properties',
- inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
- (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(MyComp, new ViewMetadata({
- template: '
',
- directives: [Location]
- }))
-
- .createAsync(MyComp)
- .then((tc) => {
-
- loader.loadNextToLocation(DynamicallyLoadedWithHostProps, tc.elementRef)
- .then(ref => {
- ref.instance.id = "new value";
-
- tc.detectChanges();
-
- var newlyInsertedElement =
- DOM.nextSibling(tc.debugElement.nativeElement);
- expect((newlyInsertedElement).id).toEqual("new value");
-
- async.done();
- });
- });
- }));
-
- it('should allow to pass projectable nodes',
- inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
- (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
- tcb.overrideView(MyComp, new ViewMetadata({template: '', directives: [Location]}))
- .createAsync(MyComp)
- .then((tc) => {
- loader.loadNextToLocation(DynamicallyLoadedWithNgContent, tc.elementRef,
- null, [[DOM.createTextNode('hello')]])
- .then(ref => {
- tc.detectChanges();
- var newlyInsertedElement =
- DOM.nextSibling(tc.debugElement.nativeElement);
- expect(newlyInsertedElement).toHaveText('dynamic(hello)');
- async.done();
- });
- });
+ tcb.createAsync(MyComp).then((tc) => {
+ tc.detectChanges();
+ loader.loadNextToLocation(DynamicallyLoadedWithNgContent,
+ tc.componentInstance.viewContainerRef, null, [])
+ .then((_) => { async.done(); });
+ });
}));
});
@@ -362,27 +208,6 @@ class ChildComp {
constructor(public elementRef: ElementRef) { this.ctxProp = 'hello'; }
}
-
-class DynamicallyCreatedComponentService {}
-
-@Component({
- selector: 'hello-cmp',
- viewProviders: [DynamicallyCreatedComponentService],
- template: "{{greeting}}"
-})
-class DynamicallyCreatedCmp implements OnDestroy {
- greeting: string;
- dynamicallyCreatedComponentService: DynamicallyCreatedComponentService;
- destroyed: boolean = false;
-
- constructor(a: DynamicallyCreatedComponentService) {
- this.greeting = "hello";
- this.dynamicallyCreatedComponentService = a;
- }
-
- ngOnDestroy() { this.destroyed = true; }
-}
-
@Component({selector: 'dummy', template: "DynamicallyLoaded;"})
class DynamicallyLoaded {
}
@@ -410,16 +235,11 @@ class DynamicallyLoadedWithNgContent {
constructor() { this.id = "default"; }
}
-@Component({selector: 'location', template: "Location;"})
-class Location {
- elementRef: ElementRef;
-
- constructor(elementRef: ElementRef) { this.elementRef = elementRef; }
-}
-
-@Component({selector: 'my-comp', directives: []})
+@Component({selector: 'my-comp', directives: [], template: ''})
class MyComp {
ctxBoolProp: boolean;
+ @ViewChild('loc', {read: ViewContainerRef}) viewContainerRef: ViewContainerRef;
+
constructor() { this.ctxBoolProp = false; }
}
diff --git a/modules/angular2/test/core/linker/query_integration_spec.ts b/modules/angular2/test/core/linker/query_integration_spec.ts
index a0c488ba38..9edf2dbafb 100644
--- a/modules/angular2/test/core/linker/query_integration_spec.ts
+++ b/modules/angular2/test/core/linker/query_integration_spec.ts
@@ -286,6 +286,99 @@ export function main() {
});
+ describe('read a different token', () => {
+ it('should contain all content children',
+ inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
+ var template =
+ '';
+
+ tcb.overrideTemplate(MyComp, template)
+ .createAsync(MyComp)
+ .then((view) => {
+ view.detectChanges();
+
+ var comp: NeedsContentChildrenWithRead =
+ view.debugElement.children[0].inject(NeedsContentChildrenWithRead);
+ expect(comp.textDirChildren.map(textDirective => textDirective.text))
+ .toEqual(['ca', 'cb']);
+
+ async.done();
+ });
+ }));
+
+ it('should contain the first content child',
+ inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
+ var template =
+ '';
+
+ tcb.overrideTemplate(MyComp, template)
+ .createAsync(MyComp)
+ .then((view) => {
+ view.detectChanges();
+
+ var comp: NeedsContentChildWithRead =
+ view.debugElement.children[0].inject(NeedsContentChildWithRead);
+ expect(comp.textDirChild.text).toEqual('ca');
+
+ async.done();
+ });
+ }));
+
+ it('should contain the first view child',
+ inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
+ var template = '';
+
+ tcb.overrideTemplate(MyComp, template)
+ .createAsync(MyComp)
+ .then((view) => {
+ view.detectChanges();
+
+ var comp: NeedsViewChildWithRead =
+ view.debugElement.children[0].inject(NeedsViewChildWithRead);
+ expect(comp.textDirChild.text).toEqual('va');
+
+ async.done();
+ });
+ }));
+
+ it('should contain all child directives in the view',
+ inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
+ var template = '';
+
+ tcb.overrideTemplate(MyComp, template)
+ .createAsync(MyComp)
+ .then((view) => {
+ view.detectChanges();
+
+ var comp: NeedsViewChildrenWithRead =
+ view.debugElement.children[0].inject(NeedsViewChildrenWithRead);
+ expect(comp.textDirChildren.map(textDirective => textDirective.text))
+ .toEqual(['va', 'vb']);
+
+ async.done();
+ });
+ }));
+
+ it('should support reading a ViewContainer',
+ inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
+ var template =
+ 'hello';
+
+ tcb.overrideTemplate(MyComp, template)
+ .createAsync(MyComp)
+ .then((view) => {
+ view.detectChanges();
+
+ var comp: NeedsViewContainerWithRead =
+ view.debugElement.children[0].inject(NeedsViewContainerWithRead);
+ comp.createView();
+ expect(view.debugElement.children[0].nativeElement).toHaveText('hello');
+
+ async.done();
+ });
+ }));
+ });
+
describe("changes", () => {
it('should notify query on change',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
@@ -923,6 +1016,47 @@ class NeedsTpl {
}
}
+@Component({selector: 'needs-content-children-read', template: ''})
+class NeedsContentChildrenWithRead {
+ @ContentChildren('q', {read: TextDirective}) textDirChildren: QueryList;
+ @ContentChildren('nonExisting', {read: TextDirective}) nonExistingVar: QueryList;
+}
+
+@Component({selector: 'needs-content-child-read', template: ''})
+class NeedsContentChildWithRead {
+ @ContentChild('q', {read: TextDirective}) textDirChild: TextDirective;
+ @ContentChild('nonExisting', {read: TextDirective}) nonExistingVar: TextDirective;
+}
+
+@Component({
+ selector: 'needs-view-children-read',
+ template: '',
+ directives: [TextDirective]
+})
+class NeedsViewChildrenWithRead {
+ @ViewChildren('q', {read: TextDirective}) textDirChildren: QueryList;
+ @ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar: QueryList;
+}
+
+@Component({
+ selector: 'needs-view-child-read',
+ template: '',
+ directives: [TextDirective]
+})
+class NeedsViewChildWithRead {
+ @ViewChild('q', {read: TextDirective}) textDirChild: TextDirective;
+ @ViewChild('nonExisting', {read: TextDirective}) nonExistingVar: TextDirective;
+}
+
+@Component({selector: 'needs-viewcontainer-read', template: ''})
+class NeedsViewContainerWithRead {
+ @ViewChild('q', {read: ViewContainerRef}) vc: ViewContainerRef;
+ @ViewChild('nonExisting', {read: ViewContainerRef}) nonExistingVar: ViewContainerRef;
+ @ContentChild(TemplateRef) template: TemplateRef;
+
+ createView() { this.vc.createEmbeddedView(this.template); }
+}
+
@Component({
selector: 'my-comp',
directives: [
@@ -946,7 +1080,12 @@ class NeedsTpl {
InertDirective,
NgIf,
NgFor,
- NeedsFourQueries
+ NeedsFourQueries,
+ NeedsContentChildrenWithRead,
+ NeedsContentChildWithRead,
+ NeedsViewChildrenWithRead,
+ NeedsViewChildWithRead,
+ NeedsViewContainerWithRead
],
template: ''
})
diff --git a/modules/angular2/test/core/linker/view_injector_integration_spec.ts b/modules/angular2/test/core/linker/view_injector_integration_spec.ts
index e207655313..c8bb0bad99 100644
--- a/modules/angular2/test/core/linker/view_injector_integration_spec.ts
+++ b/modules/angular2/test/core/linker/view_injector_integration_spec.ts
@@ -604,7 +604,7 @@ export function main() {
it("should inject TemplateRef", fakeAsync(() => {
var el = createComp('', tcb);
expect(el.childNodes[0].inject(NeedsTemplateRef).templateRef.elementRef)
- .toBe(el.childNodes[0].inject(NeedsViewContainerRef).viewContainer.element);
+ .toEqual(el.childNodes[0].inject(NeedsViewContainerRef).viewContainer.element);
}));
it("should throw if there is no TemplateRef", fakeAsync(() => {
diff --git a/modules/angular2/test/public_api_spec.ts b/modules/angular2/test/public_api_spec.ts
index 90f39a3d04..63011b2113 100644
--- a/modules/angular2/test/public_api_spec.ts
+++ b/modules/angular2/test/public_api_spec.ts
@@ -145,7 +145,6 @@ var NG_CORE = [
'APP_ID',
'AngularEntrypoint:dart',
'AbstractProviderError',
- 'AppViewManager',
'ApplicationRef',
'APPLICATION_COMMON_PROVIDERS',
'Attribute',
diff --git a/modules/angular2/test/router/integration/impl/fixture_components.ts b/modules/angular2/test/router/integration/impl/fixture_components.ts
index 26499bfefa..81aed708dd 100644
--- a/modules/angular2/test/router/integration/impl/fixture_components.ts
+++ b/modules/angular2/test/router/integration/impl/fixture_components.ts
@@ -1,4 +1,4 @@
-import {Component, ComponentRef} from 'angular2/core';
+import {Component, ComponentRef, ViewContainerRef, ViewChild} from 'angular2/core';
import {
AsyncRoute,
Route,
@@ -11,7 +11,6 @@ import {
import {PromiseWrapper} from 'angular2/src/facade/async';
import {isPresent} from 'angular2/src/facade/lang';
import {DynamicComponentLoader} from 'angular2/src/core/linker/dynamic_component_loader';
-import {ElementRef} from 'angular2/src/core/linker/element_ref';
@Component({selector: 'goodbye-cmp', template: `{{farewell}}`})
export class GoodbyeCmp {
@@ -144,16 +143,17 @@ export class RedirectToParentCmp {
@RouteConfig([new Route({path: '/', component: HelloCmp})])
export class DynamicLoaderCmp {
private _componentRef: ComponentRef = null;
- constructor(private _dynamicComponentLoader: DynamicComponentLoader,
- private _elementRef: ElementRef) {}
+ @ViewChild('viewport', {read: ViewContainerRef}) private _viewport: ViewContainerRef;
+
+ constructor(private _dynamicComponentLoader: DynamicComponentLoader) {}
onSomeAction(): Promise {
if (isPresent(this._componentRef)) {
this._componentRef.destroy();
this._componentRef = null;
}
- return this._dynamicComponentLoader.loadIntoLocation(DynamicallyLoadedComponent,
- this._elementRef, 'viewport')
+ return this._dynamicComponentLoader.loadNextToLocation(DynamicallyLoadedComponent,
+ this._viewport)
.then((cmp) => { this._componentRef = cmp; });
}
}
diff --git a/modules/angular2/test/web_workers/worker/renderer_integration_spec.ts b/modules/angular2/test/web_workers/worker/renderer_integration_spec.ts
index 82a37ab684..dc782c396f 100644
--- a/modules/angular2/test/web_workers/worker/renderer_integration_spec.ts
+++ b/modules/angular2/test/web_workers/worker/renderer_integration_spec.ts
@@ -21,7 +21,8 @@ import {
ViewMetadata,
Component,
Injectable,
- ElementRef
+ ElementRef,
+ ComponentRef
} from 'angular2/core';
import {NgIf} from 'angular2/common';
import {WebWorkerRootRenderer} from "angular2/src/web_workers/worker/renderer";
@@ -119,8 +120,8 @@ export function main() {
return uiRenderStore.deserialize(id);
}
- function getRenderer(elementRef: ElementRef) {
- return (elementRef).internalElement.parentView.renderer;
+ function getRenderer(componentRef: ComponentRef) {
+ return (componentRef.hostView).internalView.renderer;
}
it('should update text nodes',
@@ -145,8 +146,8 @@ export function main() {
{template: ''}))
.createAsync(MyComp)
.then((fixture) => {
- var checkSetters = (componentElRef, workerEl) => {
- var renderer = getRenderer(componentElRef);
+ var checkSetters = (componentRef, workerEl) => {
+ var renderer = getRenderer(componentRef);
var el = getRenderElement(workerEl);
renderer.setElementProperty(workerEl, 'tabIndex', 1);
expect((el).tabIndex).toEqual(1);
@@ -166,9 +167,9 @@ export function main() {
};
// root element
- checkSetters(fixture.elementRef, fixture.debugElement.nativeElement);
+ checkSetters(fixture.componentRef, fixture.debugElement.nativeElement);
// nested elements
- checkSetters(fixture.elementRef, fixture.debugElement.children[0].nativeElement);
+ checkSetters(fixture.componentRef, fixture.debugElement.children[0].nativeElement);
async.done();
});
@@ -220,7 +221,7 @@ export function main() {
.createAsync(MyComp)
.then((fixture) => {
var el = fixture.debugElement.children[0];
- getRenderer(fixture.elementRef)
+ getRenderer(fixture.componentRef)
.invokeElementMethod(el.nativeElement, 'setAttribute', ['a', 'b']);
expect(DOM.getAttribute(getRenderElement(el.nativeElement), 'a')).toEqual('b');
diff --git a/modules/benchmarks/src/costs/index.ts b/modules/benchmarks/src/costs/index.ts
index 4788d10036..2576e4d7cc 100644
--- a/modules/benchmarks/src/costs/index.ts
+++ b/modules/benchmarks/src/costs/index.ts
@@ -1,5 +1,5 @@
import {bootstrap} from 'angular2/platform/browser';
-import {Component, Directive, DynamicComponentLoader, ElementRef} from 'angular2/core';
+import {Component, Directive, DynamicComponentLoader, ViewContainerRef} from 'angular2/core';
import {NgIf, NgFor} from 'angular2/common';
import {ApplicationRef} from 'angular2/src/core/application_ref';
import {ListWrapper} from 'angular2/src/facade/collection';
@@ -53,7 +53,7 @@ class DummyDirective {
@Directive({selector: 'dynamic-dummy'})
class DynamicDummy {
- constructor(loader: DynamicComponentLoader, location: ElementRef) {
+ constructor(loader: DynamicComponentLoader, location: ViewContainerRef) {
loader.loadNextToLocation(DummyComponent, location);
}
}
diff --git a/tools/public_api_guard/public_api_spec.ts b/tools/public_api_guard/public_api_spec.ts
index 9631a489d8..2904c1aef6 100644
--- a/tools/public_api_guard/public_api_spec.ts
+++ b/tools/public_api_guard/public_api_spec.ts
@@ -28,9 +28,6 @@ const CORE = [
'AfterViewChecked.ngAfterViewChecked():any',
'AfterViewInit',
'AfterViewInit.ngAfterViewInit():any',
- 'AppViewManager',
- 'AppViewManager.getNamedElementInComponentView(hostLocation:ElementRef, variableName:string):ElementRef',
- 'AppViewManager.getViewContainer(location:ElementRef):ViewContainerRef',
'ApplicationRef',
'ApplicationRef.bootstrap(componentType:Type, providers:Array):Promise',
'ApplicationRef.componentTypes:Type[]',
@@ -104,10 +101,10 @@ const CORE = [
'ConcreteType',
'ContentChildMetadataFactory',
'ContentChildMetadata',
- 'ContentChildMetadata.constructor(_selector:Type|string)',
+ 'ContentChildMetadata.constructor(_selector:Type|string, {read=null}:{read?:any})',
'ContentChildrenMetadataFactory',
'ContentChildrenMetadata',
- 'ContentChildrenMetadata.constructor(_selector:Type|string, {descendants=false}:{descendants?:boolean})',
+ 'ContentChildrenMetadata.constructor(_selector:Type|string, {descendants=false,read=null}:{descendants?:boolean, read?:any})',
'CyclicDependencyError',
'CyclicDependencyError.constructor(injector:Injector, key:Key)',
'DebugNode',
@@ -161,10 +158,10 @@ const CORE = [
'DoCheck.ngDoCheck():any',
'DynamicComponentLoader',
'DynamicComponentLoader.loadAsRoot(type:Type, overrideSelectorOrNode:string, injector:Injector, onDispose:() => void, projectableNodes:any[][]):Promise',
- 'DynamicComponentLoader.loadIntoLocation(type:Type, hostLocation:ElementRef, anchorName:string, providers:ResolvedProvider[], projectableNodes:any[][]):Promise',
- 'DynamicComponentLoader.loadNextToLocation(type:Type, location:ElementRef, providers:ResolvedProvider[], projectableNodes:any[][]):Promise',
+ 'DynamicComponentLoader.loadNextToLocation(type:Type, location:ViewContainerRef, providers:ResolvedProvider[], projectableNodes:any[][]):Promise',
'ElementRef',
'ElementRef.nativeElement:any',
+ 'ElementRef.constructor(nativeElement:any)',
'EmbeddedViewRef',
'EmbeddedViewRef.hasLocal(variableName:string):boolean',
'EmbeddedViewRef.rootNodes:any[]',
@@ -344,7 +341,8 @@ const CORE = [
'QueryList.toString():string',
'QueryList',
'QueryMetadata',
- 'QueryMetadata.constructor(_selector:Type|string, {descendants=false,first=false}:{descendants?:boolean, first?:boolean})',
+ 'QueryMetadata.constructor(_selector:Type|string, {descendants=false,first=false,read=null}:{descendants?:boolean, first?:boolean, read?:any})',
+ 'QueryMetadata.read:any',
'QueryMetadata.descendants:boolean',
'QueryMetadata.first:boolean',
'QueryMetadata.isVarBindingQuery:boolean',
@@ -438,10 +436,10 @@ const CORE = [
'TypeDecorator.annotations:any[]',
'ViewChildMetadataFactory',
'ViewChildMetadata',
- 'ViewChildMetadata.constructor(_selector:Type|string)',
+ 'ViewChildMetadata.constructor(_selector:Type|string, {read=null}:{read?:any})',
'ViewChildrenMetadataFactory',
'ViewChildrenMetadata',
- 'ViewChildrenMetadata.constructor(_selector:Type|string)',
+ 'ViewChildrenMetadata.constructor(_selector:Type|string, {read=null}:{read?:any})',
'ViewContainerRef',
'ViewContainerRef.clear():void',
'ViewContainerRef.createEmbeddedView(templateRef:TemplateRef, index:number):EmbeddedViewRef',
@@ -470,7 +468,7 @@ const CORE = [
'ViewMetadata.template:string',
'ViewMetadata.templateUrl:string',
'ViewQueryMetadata',
- 'ViewQueryMetadata.constructor(_selector:Type|string, {descendants=false,first=false}:{descendants?:boolean, first?:boolean})',
+ 'ViewQueryMetadata.constructor(_selector:Type|string, {descendants=false,first=false,read=null}:{descendants?:boolean, first?:boolean, read?:any})',
'ViewQueryMetadata.isViewQuery:any',
'ViewQueryMetadata.toString():string',
'ViewRef',
@@ -844,12 +842,12 @@ const COMPILER =
'DirectiveAst.constructor(directive:CompileDirectiveMetadata, inputs:BoundDirectivePropertyAst[], hostProperties:BoundElementPropertyAst[], hostEvents:BoundEventAst[], exportAsVars:VariableAst[], sourceSpan:ParseSourceSpan)',
'DirectiveAst.visit(visitor:TemplateAstVisitor, context:any):any',
'ElementAst',
- 'ElementAst.constructor(name:string, attrs:AttrAst[], inputs:BoundElementPropertyAst[], outputs:BoundEventAst[], exportAsVars:VariableAst[], directives:DirectiveAst[], providers:ProviderAst[], children:TemplateAst[], ngContentIndex:number, sourceSpan:ParseSourceSpan)',
+ 'ElementAst.constructor(name:string, attrs:AttrAst[], inputs:BoundElementPropertyAst[], outputs:BoundEventAst[], exportAsVars:VariableAst[], directives:DirectiveAst[], providers:ProviderAst[], hasViewContainer:boolean, children:TemplateAst[], ngContentIndex:number, sourceSpan:ParseSourceSpan)',
'ElementAst.getComponent():CompileDirectiveMetadata',
'ElementAst.isBound():boolean',
'ElementAst.visit(visitor:TemplateAstVisitor, context:any):any',
'EmbeddedTemplateAst',
- 'EmbeddedTemplateAst.constructor(attrs:AttrAst[], outputs:BoundEventAst[], vars:VariableAst[], directives:DirectiveAst[], providers:ProviderAst[], children:TemplateAst[], ngContentIndex:number, sourceSpan:ParseSourceSpan)',
+ 'EmbeddedTemplateAst.constructor(attrs:AttrAst[], outputs:BoundEventAst[], vars:VariableAst[], directives:DirectiveAst[], providers:ProviderAst[], hasViewContainer:boolean, children:TemplateAst[], ngContentIndex:number, sourceSpan:ParseSourceSpan)',
'EmbeddedTemplateAst.visit(visitor:TemplateAstVisitor, context:any):any',
'NgContentAst',
'NgContentAst.constructor(index:number, ngContentIndex:number, sourceSpan:ParseSourceSpan)',
@@ -958,7 +956,8 @@ const COMPILER =
'CompileProviderMetadata.useFactory:CompileFactoryMetadata',
'CompileProviderMetadata.useValue:any',
'CompileQueryMetadata',
- 'CompileQueryMetadata.constructor({selectors,descendants,first,propertyName}:{selectors?:Array, descendants?:boolean, first?:boolean, propertyName?:string})',
+ 'CompileQueryMetadata.constructor({selectors,descendants,first,propertyName,read}:{selectors?:Array, descendants?:boolean, first?:boolean, propertyName?:string, read?:CompileTokenMetadata})',
+ 'CompileQueryMetadata.read:CompileTokenMetadata',
'CompileQueryMetadata.descendants:boolean',
'CompileQueryMetadata.first:boolean',
'CompileQueryMetadata.fromJson(data:{[key:string]:any}):CompileQueryMetadata',