refactor(core): add `Query.read` and remove `DynamicComponentLoader.loadIntoLocation`.

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.
This commit is contained in:
Tobias Bosch 2016-04-18 13:24:42 -07:00
parent c06b0a2371
commit efbd446d18
42 changed files with 608 additions and 717 deletions

View File

@ -13,7 +13,12 @@ import {
isArray isArray
} from 'angular2/src/facade/lang'; } from 'angular2/src/facade/lang';
import {unimplemented, BaseException} from 'angular2/src/facade/exceptions'; 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 { import {
ChangeDetectionStrategy, ChangeDetectionStrategy,
CHANGE_DETECTION_STRATEGY_VALUES CHANGE_DETECTION_STRATEGY_VALUES
@ -414,17 +419,20 @@ export class CompileQueryMetadata {
descendants: boolean; descendants: boolean;
first: boolean; first: boolean;
propertyName: string; propertyName: string;
read: CompileTokenMetadata;
constructor({selectors, descendants, first, propertyName}: { constructor({selectors, descendants, first, propertyName, read}: {
selectors?: Array<CompileTokenMetadata>, selectors?: Array<CompileTokenMetadata>,
descendants?: boolean, descendants?: boolean,
first?: boolean, first?: boolean,
propertyName?: string propertyName?: string,
read?: CompileTokenMetadata
} = {}) { } = {}) {
this.selectors = selectors; this.selectors = selectors;
this.descendants = normalizeBool(descendants); this.descendants = normalizeBool(descendants);
this.first = normalizeBool(first); this.first = normalizeBool(first);
this.propertyName = propertyName; this.propertyName = propertyName;
this.read = read;
} }
static fromJson(data: {[key: string]: any}): CompileQueryMetadata { static fromJson(data: {[key: string]: any}): CompileQueryMetadata {
@ -432,7 +440,8 @@ export class CompileQueryMetadata {
selectors: _arrayFromJson(data['selectors'], CompileTokenMetadata.fromJson), selectors: _arrayFromJson(data['selectors'], CompileTokenMetadata.fromJson),
descendants: data['descendants'], descendants: data['descendants'],
first: data['first'], 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), 'selectors': _arrayToJson(this.selectors),
'descendants': this.descendants, 'descendants': this.descendants,
'first': this.first, 'first': this.first,
'propertyName': this.propertyName 'propertyName': this.propertyName,
'read': _objToJson(this.read)
}; };
} }
} }

View File

@ -2,6 +2,7 @@ import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadat
import {AppView} from 'angular2/src/core/linker/view'; import {AppView} from 'angular2/src/core/linker/view';
import {StaticNodeDebugInfo, DebugContext} from 'angular2/src/core/linker/debug_context'; import {StaticNodeDebugInfo, DebugContext} from 'angular2/src/core/linker/debug_context';
import { import {
ViewUtils,
flattenNestedViewRenderNodes, flattenNestedViewRenderNodes,
interpolate, interpolate,
checkBinding checkBinding
@ -15,7 +16,6 @@ import {
ChangeDetectorState, ChangeDetectorState,
ChangeDetectionStrategy ChangeDetectionStrategy
} from 'angular2/src/core/change_detection/change_detection'; } 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 {AppElement} from 'angular2/src/core/linker/element';
import {ElementRef} from 'angular2/src/core/linker/element_ref'; import {ElementRef} from 'angular2/src/core/linker/element_ref';
import {ViewContainerRef} from 'angular2/src/core/linker/view_container_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 // Reassign the imports to different variables so we can
// define static variables with the name of the import. // define static variables with the name of the import.
// (only needed for Dart). // (only needed for Dart).
var impAppViewManager_ = AppViewManager_; var impViewUtils = ViewUtils;
var impAppView = AppView; var impAppView = AppView;
var impDebugContext = DebugContext; var impDebugContext = DebugContext;
var impAppElement = AppElement; var impAppElement = AppElement;
@ -61,10 +61,10 @@ var impInterpolate = interpolate;
var impCheckBinding = checkBinding; var impCheckBinding = checkBinding;
export class Identifiers { export class Identifiers {
static AppViewManager_ = new CompileIdentifierMetadata({ static ViewUtils = new CompileIdentifierMetadata({
name: 'AppViewManager_', name: 'ViewUtils',
moduleUrl: 'asset:angular2/lib/src/core/linker/view_manager' + MODULE_SUFFIX, moduleUrl: 'asset:angular2/lib/src/core/linker/view_utils' + MODULE_SUFFIX,
runtime: impAppViewManager_ runtime: impViewUtils
}); });
static AppView = new CompileIdentifierMetadata( static AppView = new CompileIdentifierMetadata(
{name: 'AppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: impAppView}); {name: 'AppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: impAppView});

View File

@ -65,28 +65,42 @@ export class ProviderElementContext {
private _seenProviders = new CompileTokenMap<boolean>(); private _seenProviders = new CompileTokenMap<boolean>();
private _allProviders: CompileTokenMap<ProviderAst>; private _allProviders: CompileTokenMap<ProviderAst>;
private _attrs: {[key: string]: string}; private _attrs: {[key: string]: string};
private _hasViewContainer: boolean = false;
constructor(private _viewContext: ProviderViewContext, private _parent: ProviderElementContext, constructor(private _viewContext: ProviderViewContext, private _parent: ProviderElementContext,
private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[], private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[],
attrs: AttrAst[], private _sourceSpan: ParseSourceSpan) { attrs: AttrAst[], vars: VariableAst[], private _sourceSpan: ParseSourceSpan) {
this._attrs = {}; this._attrs = {};
attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value); attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive); var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
this._allProviders = this._allProviders =
_resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors); _resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors);
this._contentQueries = _getContentQueries(directivesMeta); this._contentQueries = _getContentQueries(directivesMeta);
var queriedTokens = new CompileTokenMap<boolean>();
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 // create the providers that we know are eager first
this._allProviders.values().forEach((provider) => { this._allProviders.values().forEach((provider) => {
if (provider.eager || this.isQueried(provider.token)) { var eager = provider.eager || isPresent(queriedTokens.get(provider.token));
this._getLocalProvider(provider.providerType, provider.token, true); if (eager) {
this._getOrCreateLocalProvider(provider.providerType, provider.token, true);
} }
}); });
} }
afterElement() { afterElement() {
// collect lazy providers // collect lazy providers
this._allProviders.values().forEach( this._allProviders.values().forEach((provider) => {
(provider) => { this._getLocalProvider(provider.providerType, provider.token, false); }); this._getOrCreateLocalProvider(provider.providerType, provider.token, false);
});
} }
get transformProviders(): ProviderAst[] { return this._transformedProviders.values(); } get transformProviders(): ProviderAst[] { return this._transformedProviders.values(); }
@ -101,30 +115,42 @@ export class ProviderElementContext {
return sortedDirectives; return sortedDirectives;
} }
private isQueried(token: CompileTokenMetadata): boolean { get transformedHasViewContainer(): boolean { return this._hasViewContainer; }
private _addQueryReadsTo(token: CompileTokenMetadata, queryReadTokens: CompileTokenMap<boolean>) {
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 currentEl: ProviderElementContext = this;
var distance = 0; var distance = 0;
var queries: CompileQueryMetadata[];
while (currentEl !== null) { while (currentEl !== null) {
var localQueries = currentEl._contentQueries.get(token); queries = currentEl._contentQueries.get(token);
if (isPresent(localQueries)) { if (isPresent(queries)) {
if (localQueries.some((query) => query.descendants || distance <= 1)) { ListWrapper.addAll(result, queries.filter((query) => query.descendants || distance <= 1));
return true;
}
} }
if (currentEl._directiveAsts.length > 0) { if (currentEl._directiveAsts.length > 0) {
distance++; distance++;
} }
currentEl = currentEl._parent; currentEl = currentEl._parent;
} }
if (isPresent(this._viewContext.viewQueries.get(token))) { queries = this._viewContext.viewQueries.get(token);
return true; if (isPresent(queries)) {
ListWrapper.addAll(result, queries);
} }
return false; return result;
} }
private _getLocalProvider(requestingProviderType: ProviderAstType, token: CompileTokenMetadata, private _getOrCreateLocalProvider(requestingProviderType: ProviderAstType,
eager: boolean): ProviderAst { token: CompileTokenMetadata, eager: boolean): ProviderAst {
var resolvedProvider = this._allProviders.get(token); var resolvedProvider = this._allProviders.get(token);
if (isBlank(resolvedProvider) || if (isBlank(resolvedProvider) ||
((requestingProviderType === ProviderAstType.Directive || ((requestingProviderType === ProviderAstType.Directive ||
@ -198,17 +224,19 @@ export class ProviderElementContext {
if (dep.token.equalsTo(identifierToken(Identifiers.Renderer)) || if (dep.token.equalsTo(identifierToken(Identifiers.Renderer)) ||
dep.token.equalsTo(identifierToken(Identifiers.ElementRef)) || dep.token.equalsTo(identifierToken(Identifiers.ElementRef)) ||
dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef)) || dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef)) ||
dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef)) ||
dep.token.equalsTo(identifierToken(Identifiers.TemplateRef))) { dep.token.equalsTo(identifierToken(Identifiers.TemplateRef))) {
return dep; return dep;
} }
if (dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef))) {
this._hasViewContainer = true;
}
} }
// access the injector // access the injector
if (dep.token.equalsTo(identifierToken(Identifiers.Injector))) { if (dep.token.equalsTo(identifierToken(Identifiers.Injector))) {
return dep; return dep;
} }
// access providers // access providers
if (isPresent(this._getLocalProvider(requestingProviderType, dep.token, eager))) { if (isPresent(this._getOrCreateLocalProvider(requestingProviderType, dep.token, eager))) {
return dep; return dep;
} }
} }
@ -393,11 +421,11 @@ function _getContentQueries(
function _addQueryToTokenMap(map: CompileTokenMap<CompileQueryMetadata[]>, function _addQueryToTokenMap(map: CompileTokenMap<CompileQueryMetadata[]>,
query: CompileQueryMetadata) { query: CompileQueryMetadata) {
query.selectors.forEach((selector) => { query.selectors.forEach((token: CompileTokenMetadata) => {
var entry = map.get(selector); var entry = map.get(token);
if (isBlank(entry)) { if (isBlank(entry)) {
entry = []; entry = [];
map.add(selector, entry); map.add(token, entry);
} }
entry.push(query); entry.push(query);
}); });

View File

@ -225,8 +225,8 @@ class CompiledTemplate {
viewFactory: Function = null; viewFactory: Function = null;
proxyViewFactory: Function; proxyViewFactory: Function;
constructor() { constructor() {
this.proxyViewFactory = (viewManager, childInjector, contextEl) => this.proxyViewFactory = (viewUtils, childInjector, contextEl) =>
this.viewFactory(viewManager, childInjector, contextEl); this.viewFactory(viewUtils, childInjector, contextEl);
} }
init(viewFactory: Function) { this.viewFactory = viewFactory; } init(viewFactory: Function) { this.viewFactory = viewFactory; }

View File

@ -295,7 +295,8 @@ export class RuntimeMetadataResolver {
selectors: selectors, selectors: selectors,
first: q.first, first: q.first,
descendants: q.descendants, descendants: q.descendants,
propertyName: propertyName propertyName: propertyName,
read: isPresent(q.read) ? this.getTokenMetadata(q.read) : null
}); });
} }
} }

View File

@ -98,8 +98,9 @@ export class ElementAst implements TemplateAst {
constructor(public name: string, public attrs: AttrAst[], constructor(public name: string, public attrs: AttrAst[],
public inputs: BoundElementPropertyAst[], public outputs: BoundEventAst[], public inputs: BoundElementPropertyAst[], public outputs: BoundEventAst[],
public exportAsVars: VariableAst[], public directives: DirectiveAst[], public exportAsVars: VariableAst[], public directives: DirectiveAst[],
public providers: ProviderAst[], public children: TemplateAst[], public providers: ProviderAst[], public hasViewContainer: boolean,
public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {} public children: TemplateAst[], public ngContentIndex: number,
public sourceSpan: ParseSourceSpan) {}
visit(visitor: TemplateAstVisitor, context: any): any { visit(visitor: TemplateAstVisitor, context: any): any {
return visitor.visitElement(this, context); return visitor.visitElement(this, context);
@ -129,8 +130,8 @@ export class ElementAst implements TemplateAst {
export class EmbeddedTemplateAst implements TemplateAst { export class EmbeddedTemplateAst implements TemplateAst {
constructor(public attrs: AttrAst[], public outputs: BoundEventAst[], public vars: VariableAst[], constructor(public attrs: AttrAst[], public outputs: BoundEventAst[], public vars: VariableAst[],
public directives: DirectiveAst[], public providers: ProviderAst[], public directives: DirectiveAst[], public providers: ProviderAst[],
public children: TemplateAst[], public ngContentIndex: number, public hasViewContainer: boolean, public children: TemplateAst[],
public sourceSpan: ParseSourceSpan) {} public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
visit(visitor: TemplateAstVisitor, context: any): any { visit(visitor: TemplateAstVisitor, context: any): any {
return visitor.visitEmbeddedTemplate(this, context); return visitor.visitEmbeddedTemplate(this, context);

View File

@ -328,7 +328,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
var isViewRoot = parent.isTemplateElement || hasInlineTemplates; var isViewRoot = parent.isTemplateElement || hasInlineTemplates;
var providerContext = var providerContext =
new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot, new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot,
directiveAsts, attrs, element.sourceSpan); directiveAsts, attrs, vars, element.sourceSpan);
var children = htmlVisitAll( var children = htmlVisitAll(
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children, preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
ElementContext.create(isTemplateElement, directiveAsts, ElementContext.create(isTemplateElement, directiveAsts,
@ -355,10 +355,10 @@ class TemplateParseVisitor implements HtmlAstVisitor {
this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps, this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps,
element.sourceSpan); element.sourceSpan);
parsedElement = parsedElement = new EmbeddedTemplateAst(
new EmbeddedTemplateAst(attrs, events, vars, providerContext.transformedDirectiveAsts, attrs, events, vars, providerContext.transformedDirectiveAsts,
providerContext.transformProviders, children, providerContext.transformProviders, providerContext.transformedHasViewContainer, children,
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan); hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
} else { } else {
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan); this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
var elementExportAsVars = vars.filter(varAst => varAst.value.length === 0); var elementExportAsVars = vars.filter(varAst => varAst.value.length === 0);
@ -367,7 +367,8 @@ class TemplateParseVisitor implements HtmlAstVisitor {
parsedElement = new ElementAst( parsedElement = new ElementAst(
nodeName, attrs, elementProps, events, elementExportAsVars, nodeName, attrs, elementProps, events, elementExportAsVars,
providerContext.transformedDirectiveAsts, providerContext.transformProviders, children, providerContext.transformedDirectiveAsts, providerContext.transformProviders,
providerContext.transformedHasViewContainer, children,
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan); hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
} }
if (hasInlineTemplates) { if (hasInlineTemplates) {
@ -382,12 +383,13 @@ class TemplateParseVisitor implements HtmlAstVisitor {
templateDirectiveAsts, templateElementProps, element.sourceSpan); templateDirectiveAsts, templateElementProps, element.sourceSpan);
var templateProviderContext = new ProviderElementContext( var templateProviderContext = new ProviderElementContext(
this.providerViewContext, parent.providerContext, parent.isTemplateElement, this.providerViewContext, parent.providerContext, parent.isTemplateElement,
templateDirectiveAsts, [], element.sourceSpan); templateDirectiveAsts, [], templateVars, element.sourceSpan);
templateProviderContext.afterElement(); templateProviderContext.afterElement();
parsedElement = new EmbeddedTemplateAst([], [], templateVars, parsedElement = new EmbeddedTemplateAst([], [], templateVars,
templateProviderContext.transformedDirectiveAsts, templateProviderContext.transformedDirectiveAsts,
templateProviderContext.transformProviders, templateProviderContext.transformProviders,
templateProviderContext.transformedHasViewContainer,
[parsedElement], ngContentIndex, element.sourceSpan); [parsedElement], ngContentIndex, element.sourceSpan);
} }
return parsedElement; return parsedElement;
@ -765,8 +767,8 @@ class NonBindableVisitor implements HtmlAstVisitor {
var selector = createElementCssSelector(ast.name, attrNameAndValues); var selector = createElementCssSelector(ast.name, attrNameAndValues);
var ngContentIndex = parent.findNgContentIndex(selector); var ngContentIndex = parent.findNgContentIndex(selector);
var children = htmlVisitAll(this, ast.children, EMPTY_ELEMENT_CONTEXT); var children = htmlVisitAll(this, ast.children, EMPTY_ELEMENT_CONTEXT);
return new ElementAst(ast.name, htmlVisitAll(this, ast.attrs), [], [], [], [], [], children, return new ElementAst(ast.name, htmlVisitAll(this, ast.attrs), [], [], [], [], [], false,
ngContentIndex, ast.sourceSpan); children, ngContentIndex, ast.sourceSpan);
} }
visitComment(ast: HtmlCommentAst, context: any): any { return null; } visitComment(ast: HtmlCommentAst, context: any): any { return null; }
visitAttr(ast: HtmlAttrAst, context: any): AttrAst { visitAttr(ast: HtmlAttrAst, context: any): AttrAst {

View File

@ -30,13 +30,13 @@ export class CompileNode {
export class CompileElement extends CompileNode { export class CompileElement extends CompileNode {
static createNull(): CompileElement { 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; private _compViewExpr: o.Expression = null;
public component: CompileDirectiveMetadata = null; public appElement: o.ReadPropExpr;
private _appElement: o.Expression; public elementRef: o.Expression;
private _defaultInjector: o.Expression; public injector: o.Expression;
private _instances = new CompileTokenMap<o.Expression>(); private _instances = new CompileTokenMap<o.Expression>();
private _resolvedProviders: CompileTokenMap<ProviderAst>; private _resolvedProviders: CompileTokenMap<ProviderAst>;
@ -50,17 +50,45 @@ export class CompileElement extends CompileNode {
constructor(parent: CompileElement, view: CompileView, nodeIndex: number, constructor(parent: CompileElement, view: CompileView, nodeIndex: number,
renderNode: o.Expression, sourceAst: TemplateAst, renderNode: o.Expression, sourceAst: TemplateAst,
public component: CompileDirectiveMetadata,
private _directives: CompileDirectiveMetadata[], private _directives: CompileDirectiveMetadata[],
private _resolvedProvidersArray: ProviderAst[], private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
public hasEmbeddedView: boolean,
public variableTokens: {[key: string]: CompileTokenMetadata}) { public variableTokens: {[key: string]: CompileTokenMetadata}) {
super(parent, view, nodeIndex, renderNode, sourceAst); 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) { private _createAppElement() {
this.component = component; 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._compViewExpr = compViewExpr;
this.contentNodesByNgContentIndex = this.contentNodesByNgContentIndex =
ListWrapper.createFixedSize(component.template.ngContentSelectors.length); ListWrapper.createFixedSize(this.component.template.ngContentSelectors.length);
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) { for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
this.contentNodesByNgContentIndex[i] = []; this.contentNodesByNgContentIndex[i] = [];
} }
@ -71,7 +99,7 @@ export class CompileElement extends CompileNode {
if (isPresent(embeddedView)) { if (isPresent(embeddedView)) {
var createTemplateRefExpr = var createTemplateRefExpr =
o.importExpr(Identifiers.TemplateRef_) o.importExpr(Identifiers.TemplateRef_)
.instantiate([this.getOrCreateAppElement(), this.embeddedView.viewFactory]); .instantiate([this.appElement, this.embeddedView.viewFactory]);
var provider = new CompileProviderMetadata( var provider = new CompileProviderMetadata(
{token: identifierToken(Identifiers.TemplateRef), useValue: createTemplateRefExpr}); {token: identifierToken(Identifiers.TemplateRef), useValue: createTemplateRefExpr});
// Add TemplateRef as first provider as it does not have deps on other providers // 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 { beforeChildren(): void {
if (this.hasViewContainer) {
this._instances.add(identifierToken(Identifiers.ViewContainerRef),
this.appElement.prop('vcRef'));
}
this._resolvedProviders = new CompileTokenMap<ProviderAst>(); this._resolvedProviders = new CompileTokenMap<ProviderAst>();
this._resolvedProvidersArray.forEach(provider => this._resolvedProvidersArray.forEach(provider =>
this._resolvedProviders.add(provider.token, provider)); this._resolvedProviders.add(provider.token, provider));
@ -127,36 +160,54 @@ export class CompileElement extends CompileNode {
var directive = this._directives[i]; var directive = this._directives[i];
directive.queries.forEach((queryMeta) => { this._addQuery(queryMeta, directiveInstance); }); directive.queries.forEach((queryMeta) => { this._addQuery(queryMeta, directiveInstance); });
} }
var queriesWithReads: _QueryWithRead[] = [];
this._resolvedProviders.values().forEach((resolvedProvider) => { this._resolvedProviders.values().forEach((resolvedProvider) => {
var queriesForProvider = this._getQueriesFor(resolvedProvider.token); var queriesForProvider = this._getQueriesFor(resolvedProvider.token);
var providerExpr = this._instances.get(resolvedProvider.token); ListWrapper.addAll(
queriesForProvider.forEach((query) => { query.addValue(providerExpr, this.view); }); queriesWithReads,
queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
}); });
StringMapWrapper.forEach(this.variableTokens, (_, varName) => { StringMapWrapper.forEach(this.variableTokens, (_, varName) => {
var token = this.variableTokens[varName]; var token = this.variableTokens[varName];
var varValue; var varValue;
var varValueForQuery;
if (isPresent(token)) { if (isPresent(token)) {
varValue = varValueForQuery = this._instances.get(token); varValue = this._instances.get(token);
} else { } else {
varValueForQuery = this.getOrCreateAppElement().prop('ref');
varValue = this.renderNode; varValue = this.renderNode;
} }
this.view.variables.set(varName, varValue); this.view.variables.set(varName, varValue);
this.view.namedAppElements.push([varName, this.getOrCreateAppElement()]); var varToken = new CompileTokenMetadata({value: varName});
ListWrapper.addAll(queriesWithReads, this._getQueriesFor(varToken)
var queriesForProvider = this._getQueriesFor(new CompileTokenMetadata({value: varName})); .map(query => new _QueryWithRead(query, varToken)));
queriesForProvider.forEach((query) => { query.addValue(varValueForQuery, this.view); });
}); });
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)) { if (isPresent(this.component)) {
var componentConstructorViewQueryList = var componentConstructorViewQueryList =
isPresent(this.component) ? o.literalArr(this._componentConstructorViewQueryLists) : isPresent(this.component) ? o.literalArr(this._componentConstructorViewQueryLists) :
o.NULL_EXPR; o.NULL_EXPR;
var compExpr = isPresent(this.getComponent()) ? this.getComponent() : o.NULL_EXPR; var compExpr = isPresent(this.getComponent()) ? this.getComponent() : o.NULL_EXPR;
this.view.createMethod.addStmt( this.view.createMethod.addStmt(
this.getOrCreateAppElement() this.appElement.callMethod(
.callMethod('initComponent', 'initComponent',
[compExpr, componentConstructorViewQueryList, this._compViewExpr]) [compExpr, componentConstructorViewQueryList, this._compViewExpr])
.toStmt()); .toStmt());
} }
} }
@ -202,43 +253,6 @@ export class CompileElement extends CompileNode {
return res; 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[] { private _getQueriesFor(token: CompileTokenMetadata): CompileQuery[] {
var result: CompileQuery[] = []; var result: CompileQuery[] = [];
var currentEl: CompileElement = this; var currentEl: CompileElement = this;
@ -289,30 +303,20 @@ export class CompileElement extends CompileNode {
} }
if (isPresent(dep.token)) { if (isPresent(dep.token)) {
// access builtins // access builtins with special visibility
if (isBlank(result)) { if (isBlank(result)) {
if (dep.token.equalsTo(identifierToken(Identifiers.Renderer))) { if (dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef))) {
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 (requestingProviderType === ProviderAstType.Component) { if (requestingProviderType === ProviderAstType.Component) {
return this._compViewExpr.prop('ref'); return this._compViewExpr.prop('ref');
} else { } else {
return o.THIS_EXPR.prop('ref'); 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)) { if (isBlank(result)) {
result = this._instances.get(dep.token); result = this._instances.get(dep.token);
} }
// access the injector
if (isBlank(result) && dep.token.equalsTo(identifierToken(Identifiers.Injector))) {
result = this.getOrCreateInjector();
}
} }
return result; return result;
} }
@ -400,3 +404,10 @@ function createProviderProperty(propName: string, provider: ProviderAst,
} }
return o.THIS_EXPR.prop(propName); 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;
}
}

View File

@ -77,7 +77,7 @@ export class CompileQuery {
function createQueryValues(viewValues: ViewQueryValues): o.Expression[] { function createQueryValues(viewValues: ViewQueryValues): o.Expression[] {
return ListWrapper.flatten(viewValues.values.map((entry) => { return ListWrapper.flatten(viewValues.values.map((entry) => {
if (entry instanceof ViewQueryValues) { if (entry instanceof ViewQueryValues) {
return mapNestedViews(entry.view.declarationElement.getOrCreateAppElement(), entry.view, return mapNestedViews(entry.view.declarationElement.appElement, entry.view,
createQueryValues(entry)); createQueryValues(entry));
} else { } else {
return <o.Expression>entry; return <o.Expression>entry;

View File

@ -33,9 +33,9 @@ export class CompilePipe {
export class CompileView implements NameResolver { export class CompileView implements NameResolver {
public viewType: ViewType; public viewType: ViewType;
public viewQueries: CompileTokenMap<CompileQuery[]>; public viewQueries: CompileTokenMap<CompileQuery[]>;
public namedAppElements: Array<Array<string | o.Expression>> = [];
public nodes: CompileNode[] = []; public nodes: CompileNode[] = [];
// root nodes or AppElements for ViewContainers
public rootNodesOrAppElements: o.Expression[] = []; public rootNodesOrAppElements: o.Expression[] = [];
public bindings: CompileBinding[] = []; public bindings: CompileBinding[] = [];

View File

@ -59,7 +59,7 @@ export class ChangeDetectionStrategyEnum {
} }
export class ViewConstructorVars { export class ViewConstructorVars {
static viewManager = o.variable('viewManager'); static viewUtils = o.variable('viewUtils');
static parentInjector = o.variable('parentInjector'); static parentInjector = o.variable('parentInjector');
static declarationEl = o.variable('declarationEl'); static declarationEl = o.variable('declarationEl');
} }
@ -67,7 +67,7 @@ export class ViewConstructorVars {
export class ViewProperties { export class ViewProperties {
static renderer = o.THIS_EXPR.prop('renderer'); static renderer = o.THIS_EXPR.prop('renderer');
static projectableNodes = o.THIS_EXPR.prop('projectableNodes'); 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'); } export class EventHandlerVars { static event = o.variable('$event'); }

View File

@ -67,10 +67,9 @@ export class CompileEventListener {
} }
finishMethod() { finishMethod() {
var markPathToRootStart = var markPathToRootStart = this._hasComponentHostListener ?
this._hasComponentHostListener ? this.compileElement.appElement.prop('componentView') :
this.compileElement.getOrCreateAppElement().prop('componentView') : o.THIS_EXPR;
o.THIS_EXPR;
var resultExpr: o.Expression = o.literal(true); var resultExpr: o.Expression = o.literal(true);
this._actionResultExprs.forEach((expr) => { resultExpr = resultExpr.and(expr); }); this._actionResultExprs.forEach((expr) => { resultExpr = resultExpr.and(expr); });
var stmts = var stmts =

View File

@ -189,8 +189,7 @@ export function bindDirectiveInputs(directiveAst: DirectiveAst, directiveInstanc
}); });
if (isOnPushComp) { if (isOnPushComp) {
detectChangesInInputsMethod.addStmt(new o.IfStmt(DetectChangesVars.changed, [ detectChangesInInputsMethod.addStmt(new o.IfStmt(DetectChangesVars.changed, [
compileElement.getOrCreateAppElement() compileElement.appElement.prop('componentView')
.prop('componentView')
.callMethod('markAsCheckOnce', []) .callMethod('markAsCheckOnce', [])
.toStmt() .toStmt()
])); ]));

View File

@ -92,14 +92,15 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
private _addRootNodeAndProject(node: CompileNode, ngContentIndex: number, private _addRootNodeAndProject(node: CompileNode, ngContentIndex: number,
parent: CompileElement) { parent: CompileElement) {
var appEl = node instanceof CompileElement ? node.getOptionalAppElement() : null; var vcAppEl =
(node instanceof CompileElement && node.hasViewContainer) ? node.appElement : null;
if (this._isRootNode(parent)) { 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) { 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)) { } 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( this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderElement), new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderElement),
[o.StmtModifier.Private])); [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); var renderNode = o.THIS_EXPR.prop(fieldName);
@ -204,7 +205,6 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
var directives = ast.directives.map(directiveAst => directiveAst.directive); var directives = ast.directives.map(directiveAst => directiveAst.directive);
var variables = var variables =
_readHtmlAndDirectiveVariables(ast.exportAsVars, ast.directives, this.view.viewType); _readHtmlAndDirectiveVariables(ast.exportAsVars, ast.directives, this.view.viewType);
this.view.createMethod.addStmt(createRenderNode);
var htmlAttrs = _readHtmlAttrs(ast.attrs); var htmlAttrs = _readHtmlAttrs(ast.attrs);
var attrNameAndValues = _mergeHtmlAndDirectiveAttrs(htmlAttrs, directives); var attrNameAndValues = _mergeHtmlAndDirectiveAttrs(htmlAttrs, directives);
for (var i = 0; i < attrNameAndValues.length; i++) { for (var i = 0; i < attrNameAndValues.length; i++) {
@ -216,8 +216,9 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
[renderNode, o.literal(attrName), o.literal(attrValue)]) [renderNode, o.literal(attrName), o.literal(attrValue)])
.toStmt()); .toStmt());
} }
var compileElement = new CompileElement(parent, this.view, nodeIndex, renderNode, ast, var compileElement =
directives, ast.providers, variables); new CompileElement(parent, this.view, nodeIndex, renderNode, ast, component, directives,
ast.providers, ast.hasViewContainer, false, variables);
this.view.nodes.push(compileElement); this.view.nodes.push(compileElement);
var compViewExpr: o.ReadVarExpr = null; var compViewExpr: o.ReadVarExpr = null;
if (isPresent(component)) { if (isPresent(component)) {
@ -225,14 +226,14 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
new CompileIdentifierMetadata({name: getViewFactoryName(component, 0)}); new CompileIdentifierMetadata({name: getViewFactoryName(component, 0)});
this.targetDependencies.push(new ViewCompileDependency(component, nestedComponentIdentifier)); this.targetDependencies.push(new ViewCompileDependency(component, nestedComponentIdentifier));
compViewExpr = o.variable(`compView_${nodeIndex}`); compViewExpr = o.variable(`compView_${nodeIndex}`);
compileElement.setComponentView(compViewExpr);
this.view.createMethod.addStmt(compViewExpr.set(o.importExpr(nestedComponentIdentifier) this.view.createMethod.addStmt(compViewExpr.set(o.importExpr(nestedComponentIdentifier)
.callFn([ .callFn([
ViewProperties.viewManager, ViewProperties.viewUtils,
compileElement.getOrCreateInjector(), compileElement.injector,
compileElement.getOrCreateAppElement() compileElement.appElement
])) ]))
.toDeclStmt()); .toDeclStmt());
compileElement.setComponent(component, compViewExpr);
} }
compileElement.beforeChildren(); compileElement.beforeChildren();
this._addRootNodeAndProject(compileElement, ast.ngContentIndex, parent); this._addRootNodeAndProject(compileElement, ast.ngContentIndex, parent);
@ -259,24 +260,25 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
this.view.fields.push( this.view.fields.push(
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderComment), new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderComment),
[o.StmtModifier.Private])); [o.StmtModifier.Private]));
var createRenderNode = o.THIS_EXPR.prop(fieldName) this.view.createMethod.addStmt(
.set(ViewProperties.renderer.callMethod( o.THIS_EXPR.prop(fieldName)
'createTemplateAnchor', .set(ViewProperties.renderer.callMethod(
[ 'createTemplateAnchor',
this._getParentRenderNode(parent), [
this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast) this._getParentRenderNode(parent),
])) this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast)
.toStmt(); ]))
.toStmt());
var renderNode = o.THIS_EXPR.prop(fieldName); var renderNode = o.THIS_EXPR.prop(fieldName);
var templateVariableBindings = ast.vars.map( var templateVariableBindings = ast.vars.map(
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]); varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
var directives = ast.directives.map(directiveAst => directiveAst.directive); var directives = ast.directives.map(directiveAst => directiveAst.directive);
var compileElement = new CompileElement(parent, this.view, nodeIndex, renderNode, ast, var compileElement =
directives, ast.providers, {}); new CompileElement(parent, this.view, nodeIndex, renderNode, ast, null, directives,
ast.providers, ast.hasViewContainer, true, {});
this.view.nodes.push(compileElement); this.view.nodes.push(compileElement);
this.view.createMethod.addStmt(createRenderNode);
this.nestedViewCount++; this.nestedViewCount++;
var embeddedView = new CompileView( var embeddedView = new CompileView(
@ -413,7 +415,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
var emptyTemplateVariableBindings = var emptyTemplateVariableBindings =
view.templateVariableBindings.map((entry) => [entry[0], o.NULL_EXPR]); view.templateVariableBindings.map((entry) => [entry[0], o.NULL_EXPR]);
var viewConstructorArgs = [ 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.parentInjector.name, o.importType(Identifiers.Injector)),
new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement)) new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement))
]; ];
@ -423,7 +425,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
renderCompTypeVar, renderCompTypeVar,
ViewTypeEnum.fromValue(view.viewType), ViewTypeEnum.fromValue(view.viewType),
o.literalMap(emptyTemplateVariableBindings), o.literalMap(emptyTemplateVariableBindings),
ViewConstructorVars.viewManager, ViewConstructorVars.viewUtils,
ViewConstructorVars.parentInjector, ViewConstructorVars.parentInjector,
ViewConstructorVars.declarationEl, ViewConstructorVars.declarationEl,
ChangeDetectionStrategyEnum.fromValue(getChangeDetectionMode(view)), ChangeDetectionStrategyEnum.fromValue(getChangeDetectionMode(view)),
@ -462,7 +464,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
function createViewFactory(view: CompileView, viewClass: o.ClassStmt, function createViewFactory(view: CompileView, viewClass: o.ClassStmt,
renderCompTypeVar: o.ReadVarExpr): o.Statement { renderCompTypeVar: o.ReadVarExpr): o.Statement {
var viewFactoryArgs = [ 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.parentInjector.name, o.importType(Identifiers.Injector)),
new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement)) new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement))
]; ];
@ -478,15 +480,16 @@ function createViewFactory(view: CompileView, viewClass: o.ClassStmt,
initRenderCompTypeStmts = [ initRenderCompTypeStmts = [
new o.IfStmt(renderCompTypeVar.identical(o.NULL_EXPR), new o.IfStmt(renderCompTypeVar.identical(o.NULL_EXPR),
[ [
renderCompTypeVar.set(ViewConstructorVars.viewManager renderCompTypeVar.set(ViewConstructorVars
.callMethod('createRenderComponentType', .viewUtils.callMethod('createRenderComponentType',
[ [
o.literal(templateUrlInfo), o.literal(templateUrlInfo),
o.literal( o.literal(view.component
view.component.template.ngContentSelectors.length), .template.ngContentSelectors.length),
ViewEncapsulationEnum.fromValue(view.component.template.encapsulation), ViewEncapsulationEnum
view.styles .fromValue(view.component.template.encapsulation),
])) view.styles
]))
.toStmt() .toStmt()
]) ])
]; ];
@ -513,7 +516,7 @@ function generateCreateMethod(view: CompileView): o.Statement[] {
} }
var resultExpr: o.Expression; var resultExpr: o.Expression;
if (view.viewType === ViewType.HOST) { if (view.viewType === ViewType.HOST) {
resultExpr = (<CompileElement>view.nodes[0]).getOrCreateAppElement(); resultExpr = (<CompileElement>view.nodes[0]).appElement;
} else { } else {
resultExpr = o.NULL_EXPR; resultExpr = o.NULL_EXPR;
} }
@ -523,7 +526,6 @@ function generateCreateMethod(view: CompileView): o.Statement[] {
[ [
createFlatArray(view.rootNodesOrAppElements), createFlatArray(view.rootNodesOrAppElements),
o.literalArr(view.nodes.map(node => node.renderNode)), o.literalArr(view.nodes.map(node => node.renderNode)),
o.literalMap(view.namedAppElements),
o.literalArr(view.disposables), o.literalArr(view.disposables),
o.literalArr(view.subscriptions) o.literalArr(view.subscriptions)
]) ])

View File

@ -11,8 +11,7 @@ import {
KeyValueDiffers, KeyValueDiffers,
defaultKeyValueDiffers defaultKeyValueDiffers
} from './change_detection/change_detection'; } from './change_detection/change_detection';
import {AppViewManager} from './linker/view_manager'; import {ViewUtils} from "./linker/view_utils";
import {AppViewManager_} from "./linker/view_manager";
import {ComponentResolver} from './linker/component_resolver'; import {ComponentResolver} from './linker/component_resolver';
import {ReflectorComponentResolver} from "./linker/component_resolver"; import {ReflectorComponentResolver} from "./linker/component_resolver";
import {DynamicComponentLoader} from './linker/dynamic_component_loader'; 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<Type | Provider | any[]> = CONST_EXPR([ export const APPLICATION_COMMON_PROVIDERS: Array<Type | Provider | any[]> = CONST_EXPR([
new Provider(ComponentResolver, {useClass: ReflectorComponentResolver}), new Provider(ComponentResolver, {useClass: ReflectorComponentResolver}),
APP_ID_RANDOM_PROVIDER, APP_ID_RANDOM_PROVIDER,
new Provider(AppViewManager, {useClass: AppViewManager_}), ViewUtils,
new Provider(IterableDiffers, {useValue: defaultIterableDiffers}), new Provider(IterableDiffers, {useValue: defaultIterableDiffers}),
new Provider(KeyValueDiffers, {useValue: defaultKeyValueDiffers}), new Provider(KeyValueDiffers, {useValue: defaultKeyValueDiffers}),
new Provider(DynamicComponentLoader, {useClass: DynamicComponentLoader_}) new Provider(DynamicComponentLoader, {useClass: DynamicComponentLoader_})

View File

@ -1,6 +1,5 @@
// Public API for compiler // Public API for compiler
export {ComponentResolver} from './linker/component_resolver'; export {ComponentResolver} from './linker/component_resolver';
export {AppViewManager} from './linker/view_manager';
export {QueryList} from './linker/query_list'; export {QueryList} from './linker/query_list';
export {DynamicComponentLoader} from './linker/dynamic_component_loader'; export {DynamicComponentLoader} from './linker/dynamic_component_loader';
export {ElementRef} from './linker/element_ref'; export {ElementRef} from './linker/element_ref';

View File

@ -1,10 +1,10 @@
import {Injector} from 'angular2/src/core/di'; import {Injector} from 'angular2/src/core/di';
import {Type, CONST, isPresent, isBlank} from 'angular2/src/facade/lang'; import {Type, CONST, isPresent, isBlank} from 'angular2/src/facade/lang';
import {unimplemented} from 'angular2/src/facade/exceptions'; 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 {ViewRef, ViewRef_} from './view_ref';
import {AppElement} from './element'; import {AppElement} from './element';
import {AppViewManager} from './view_manager'; import {ViewUtils} from './view_utils';
import {ChangeDetectorRef} from '../change_detection/change_detection'; import {ChangeDetectorRef} from '../change_detection/change_detection';
/** /**
@ -38,7 +38,7 @@ export abstract class ComponentRef {
/** /**
* The {@link ChangeDetectorRef} of the Component instance. * The {@link ChangeDetectorRef} of the Component instance.
*/ */
get changeDetectorRef(): ChangeDetectorRef { return unimplemented(); }; get changeDetectorRef(): ChangeDetectorRef { return unimplemented(); }
/** /**
* The component type. * The component type.
@ -57,15 +57,15 @@ export abstract class ComponentRef {
} }
export class ComponentRef_ extends ComponentRef { export class ComponentRef_ extends ComponentRef {
constructor(private _location: AppElement, private _componentType: Type) { super(); } constructor(private _hostElement: AppElement, private _componentType: Type) { super(); }
get location(): ElementRef { return this._location.ref; } get location(): ElementRef { return this._hostElement.elementRef; }
get injector(): Injector { return this._location.injector; } get injector(): Injector { return this._hostElement.injector; }
get instance(): any { return this._location.component; }; get instance(): any { return this._hostElement.component; };
get hostView(): ViewRef { return this._location.parentView.ref; }; get hostView(): ViewRef { return this._hostElement.parentView.ref; };
get changeDetectorRef(): ChangeDetectorRef { return this.hostView; }; get changeDetectorRef(): ChangeDetectorRef { return this.hostView; };
get componentType(): Type { return this._componentType; } 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); } onDestroy(callback: Function): void { this.hostView.onDestroy(callback); }
} }
@ -81,12 +81,12 @@ export class ComponentFactory {
*/ */
create(injector: Injector, projectableNodes: any[][] = null, create(injector: Injector, projectableNodes: any[][] = null,
rootSelectorOrNode: string | any = null): ComponentRef { rootSelectorOrNode: string | any = null): ComponentRef {
var vm: AppViewManager = injector.get(AppViewManager); var vu: ViewUtils = injector.get(ViewUtils);
if (isBlank(projectableNodes)) { if (isBlank(projectableNodes)) {
projectableNodes = []; projectableNodes = [];
} }
// Note: Host views don't need a declarationAppElement! // 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); var hostElement = hostView.create(projectableNodes, rootSelectorOrNode);
return new ComponentRef_(hostElement, this._componentType); return new ComponentRef_(hostElement, this._componentType);
} }

View File

@ -1,9 +1,8 @@
import {Key, Injector, ResolvedProvider, Provider, provide, Injectable} from 'angular2/src/core/di'; import {Key, Injector, ResolvedProvider, Provider, provide, Injectable} from 'angular2/src/core/di';
import {ComponentResolver} from './component_resolver'; import {ComponentResolver} from './component_resolver';
import {isType, Type, stringify, isPresent} from 'angular2/src/facade/lang'; 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 {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. * 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, abstract loadAsRoot(type: Type, overrideSelectorOrNode: string | any, injector: Injector,
onDispose?: () => void, projectableNodes?: any[][]): Promise<ComponentRef>; onDispose?: () => void, projectableNodes?: any[][]): Promise<ComponentRef>;
/**
* 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 (<div #child></div>)'
* })
* class MyApp {
* constructor(dcl: DynamicComponentLoader, elementRef: ElementRef) {
* dcl.loadIntoLocation(ChildComponent, elementRef, 'child');
* }
* }
*
* bootstrap(MyApp);
* ```
*
* Resulting DOM:
*
* ```
* <my-app>
* Parent (
* <div #child="" class="ng-binding"></div>
* <child-component class="ng-binding">Child</child-component>
* )
* </my-app>
* ```
*/
abstract loadIntoLocation(type: Type, hostLocation: ElementRef, anchorName: string,
providers?: ResolvedProvider[],
projectableNodes?: any[][]): Promise<ComponentRef>;
/** /**
* Creates an instance of a Component and attaches it to the View Container found at the * 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 * You can optionally provide `providers` to configure the {@link Injector} provisioned for this
* Component Instance. * Component Instance.
@ -137,8 +85,8 @@ export abstract class DynamicComponentLoader {
* template: 'Parent' * template: 'Parent'
* }) * })
* class MyApp { * class MyApp {
* constructor(dcl: DynamicComponentLoader, elementRef: ElementRef) { * constructor(dcl: DynamicComponentLoader, viewContainerRef: ViewContainerRef) {
* dcl.loadNextToLocation(ChildComponent, elementRef); * dcl.loadNextToLocation(ChildComponent, viewContainerRef);
* } * }
* } * }
* *
@ -152,15 +100,14 @@ export abstract class DynamicComponentLoader {
* <child-component>Child</child-component> * <child-component>Child</child-component>
* ``` * ```
*/ */
abstract loadNextToLocation(type: Type, location: ElementRef, providers?: ResolvedProvider[], abstract loadNextToLocation(type: Type, location: ViewContainerRef,
providers?: ResolvedProvider[],
projectableNodes?: any[][]): Promise<ComponentRef>; projectableNodes?: any[][]): Promise<ComponentRef>;
} }
@Injectable() @Injectable()
export class DynamicComponentLoader_ extends DynamicComponentLoader { export class DynamicComponentLoader_ extends DynamicComponentLoader {
constructor(private _compiler: ComponentResolver, private _viewManager: AppViewManager) { constructor(private _compiler: ComponentResolver) { super(); }
super();
}
loadAsRoot(type: Type, overrideSelectorOrNode: string | any, injector: Injector, loadAsRoot(type: Type, overrideSelectorOrNode: string | any, injector: Injector,
onDispose?: () => void, projectableNodes?: any[][]): Promise<ComponentRef> { onDispose?: () => void, projectableNodes?: any[][]): Promise<ComponentRef> {
@ -175,20 +122,11 @@ export class DynamicComponentLoader_ extends DynamicComponentLoader {
}); });
} }
loadIntoLocation(type: Type, hostLocation: ElementRef, anchorName: string, loadNextToLocation(type: Type, location: ViewContainerRef, providers: ResolvedProvider[] = null,
providers: ResolvedProvider[] = null,
projectableNodes: any[][] = null): Promise<ComponentRef> {
return this.loadNextToLocation(
type, this._viewManager.getNamedElementInComponentView(hostLocation, anchorName), providers,
projectableNodes);
}
loadNextToLocation(type: Type, location: ElementRef, providers: ResolvedProvider[] = null,
projectableNodes: any[][] = null): Promise<ComponentRef> { projectableNodes: any[][] = null): Promise<ComponentRef> {
return this._compiler.resolveComponent(type).then(componentFactory => { return this._compiler.resolveComponent(type).then(componentFactory => {
var viewContainer = this._viewManager.getViewContainer(location); return location.createComponent(componentFactory, location.length, providers,
return viewContainer.createComponent(componentFactory, viewContainer.length, providers, projectableNodes);
projectableNodes);
}); });
} }
} }

View File

@ -6,37 +6,30 @@ import {Injector} from 'angular2/src/core/di';
import {AppView} from './view'; import {AppView} from './view';
import {ViewType} from './view_type'; import {ViewType} from './view_type';
import {ElementRef_} from './element_ref'; import {ElementRef} from './element_ref';
import {ViewContainerRef, ViewContainerRef_} from './view_container_ref'; import {ViewContainerRef, ViewContainerRef_} from './view_container_ref';
import {QueryList} from './query_list'; import {QueryList} from './query_list';
/**
* An AppElement is created for elements that have a ViewContainerRef,
* a nested component or a <template> element to keep data around
* that is needed for later instantiations.
*/
export class AppElement { export class AppElement {
public nestedViews: AppView<any>[] = null; public nestedViews: AppView<any>[] = null;
public componentView: AppView<any> = null; public componentView: AppView<any> = null;
private _ref: ElementRef_;
private _vcRef: ViewContainerRef_;
public component: any; public component: any;
public componentConstructorViewQueries: QueryList<any>[]; public componentConstructorViewQueries: QueryList<any>[];
constructor(public index: number, public parentIndex: number, public parentView: AppView<any>, constructor(public index: number, public parentIndex: number, public parentView: AppView<any>,
public nativeElement: any) {} public nativeElement: any) {}
get ref(): ElementRef_ { get elementRef(): ElementRef { return new ElementRef(this.nativeElement); }
if (isBlank(this._ref)) {
this._ref = new ElementRef_(this);
}
return this._ref;
}
get vcRef(): ViewContainerRef_ { get vcRef(): ViewContainerRef_ { return new ViewContainerRef_(this); }
if (isBlank(this._vcRef)) {
this._vcRef = new ViewContainerRef_(this);
}
return this._vcRef;
}
initComponent(component: any, componentConstructorViewQueries: QueryList<any>[], initComponent(component: any, componentConstructorViewQueries: QueryList<any>[],
view: AppView<any>) { view: AppView<any>) {

View File

@ -10,7 +10,7 @@ import {AppElement} from './element';
// Note: We don't expose things like `Injector`, `ViewContainer`, ... here, // 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 // 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. // 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 * 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). * (e.g. when the application runs in a web worker).
@ -30,13 +30,7 @@ export abstract class ElementRef {
* </p> * </p>
* </div> * </div>
*/ */
get nativeElement(): any { return unimplemented(); } public nativeElement: any;
}
constructor(nativeElement: any) { this.nativeElement = nativeElement; }
export class ElementRef_ implements ElementRef {
constructor(private _element: AppElement) {}
get internalElement(): AppElement { return this._element; }
get nativeElement() { return this._element.nativeElement; }
} }

View File

@ -1,4 +1,4 @@
import {ElementRef, ElementRef_} from './element_ref'; import {ElementRef} from './element_ref';
import {AppElement} from './element'; import {AppElement} from './element';
import {AppView} from './view'; import {AppView} from './view';
import {EmbeddedViewRef} from './view_ref'; import {EmbeddedViewRef} from './view_ref';
@ -37,11 +37,11 @@ export class TemplateRef_ extends TemplateRef {
constructor(private _appElement: AppElement, private _viewFactory: Function) { super(); } constructor(private _appElement: AppElement, private _viewFactory: Function) { super(); }
createEmbeddedView(): EmbeddedViewRef { createEmbeddedView(): EmbeddedViewRef {
var view: AppView<any> = this._viewFactory(this._appElement.parentView.viewManager, var view: AppView<any> = this._viewFactory(this._appElement.parentView.viewUtils,
this._appElement.parentInjector, this._appElement); this._appElement.parentInjector, this._appElement);
view.create(null, null); view.create(null, null);
return view.ref; return view.ref;
} }
get elementRef(): ElementRef { return this._appElement.ref; } get elementRef(): ElementRef { return this._appElement.elementRef; }
} }

View File

@ -27,9 +27,9 @@ import {ObservableWrapper} from 'angular2/src/facade/async';
import {Renderer, RootRenderer, RenderComponentType} from 'angular2/src/core/render/api'; import {Renderer, RootRenderer, RenderComponentType} from 'angular2/src/core/render/api';
import {ViewRef_} from './view_ref'; import {ViewRef_} from './view_ref';
import {AppViewManager_, AppViewManager} from './view_manager';
import {ViewType} from './view_type'; import {ViewType} from './view_type';
import { import {
ViewUtils,
flattenNestedViewRenderNodes, flattenNestedViewRenderNodes,
ensureSlotCount, ensureSlotCount,
arrayLooseIdentical, arrayLooseIdentical,
@ -65,7 +65,6 @@ export abstract class AppView<T> {
allNodes: any[]; allNodes: any[];
disposables: Function[]; disposables: Function[];
subscriptions: any[]; subscriptions: any[];
namedAppElements: {[key: string]: AppElement};
contentChildren: AppView<any>[] = []; contentChildren: AppView<any>[] = [];
viewChildren: AppView<any>[] = []; viewChildren: AppView<any>[] = [];
renderParent: AppView<any>; renderParent: AppView<any>;
@ -95,13 +94,13 @@ export abstract class AppView<T> {
private _hasExternalHostElement: boolean; private _hasExternalHostElement: boolean;
constructor(public clazz: any, public componentType: RenderComponentType, public type: ViewType, 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 parentInjector: Injector, public declarationAppElement: AppElement,
public cdMode: ChangeDetectionStrategy, literalArrayCacheSize: number, public cdMode: ChangeDetectionStrategy, literalArrayCacheSize: number,
literalMapCacheSize: number, public staticNodeDebugInfos: StaticNodeDebugInfo[]) { literalMapCacheSize: number, public staticNodeDebugInfos: StaticNodeDebugInfo[]) {
this.ref = new ViewRef_(this); this.ref = new ViewRef_(this);
if (type === ViewType.COMPONENT || type === ViewType.HOST) { if (type === ViewType.COMPONENT || type === ViewType.HOST) {
this.renderer = viewManager.renderComponent(componentType); this.renderer = viewUtils.renderComponent(componentType);
} else { } else {
this.renderer = declarationAppElement.parentView.renderer; this.renderer = declarationAppElement.parentView.renderer;
} }
@ -145,15 +144,15 @@ export abstract class AppView<T> {
} }
/** /**
* Overwritten by implementations * Overwritten by implementations.
* Returns the AppElement for the host element for ViewType.HOST.
*/ */
createInternal(rootSelectorOrNode: string | any): AppElement { return null; } createInternal(rootSelectorOrNode: string | any): AppElement { return null; }
init(rootNodesOrAppElements: any[], allNodes: any[], appElements: {[key: string]: AppElement}, init(rootNodesOrAppElements: any[], allNodes: any[], disposables: Function[],
disposables: Function[], subscriptions: any[]) { subscriptions: any[]) {
this.rootNodesOrAppElements = rootNodesOrAppElements; this.rootNodesOrAppElements = rootNodesOrAppElements;
this.allNodes = allNodes; this.allNodes = allNodes;
this.namedAppElements = appElements;
this.disposables = disposables; this.disposables = disposables;
this.subscriptions = subscriptions; this.subscriptions = subscriptions;
if (this.type === ViewType.COMPONENT) { if (this.type === ViewType.COMPONENT) {

View File

@ -7,7 +7,7 @@ import {wtfCreateScope, wtfLeave, WtfScopeFn} from '../profile/profile';
import {AppElement} from './element'; import {AppElement} from './element';
import {ElementRef, ElementRef_} from './element_ref'; import {ElementRef} from './element_ref';
import {TemplateRef, TemplateRef_} from './template_ref'; import {TemplateRef, TemplateRef_} from './template_ref';
import {EmbeddedViewRef, ViewRef, ViewRef_} from './view_ref'; import {EmbeddedViewRef, ViewRef, ViewRef_} from './view_ref';
import {ComponentFactory, ComponentRef} from './component_factory'; import {ComponentFactory, ComponentRef} from './component_factory';
@ -27,10 +27,7 @@ import {ComponentFactory, ComponentRef} from './component_factory';
* the Rendered View. * the Rendered View.
* *
* To access a `ViewContainerRef` of an Element, you can either place a {@link Directive} injected * 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 * with `ViewContainerRef` on the Element, or you obtain it via a {@link ViewChild} query.
* {@link AppViewManager#getViewContainer}.
*
* <!-- TODO(i): we are also considering ElementRef#viewContainer api -->
*/ */
export abstract class ViewContainerRef { export abstract class ViewContainerRef {
/** /**
@ -121,7 +118,7 @@ export class ViewContainerRef_ implements ViewContainerRef {
return isPresent(views) ? views.length : 0; 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 // TODO(rado): profile and decide whether bounds checks should be added
// to the methods below. // to the methods below.

View File

@ -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 (<ElementRef_>location).internalElement.vcRef;
}
getNamedElementInComponentView(hostLocation: ElementRef, variableName: string): ElementRef {
var appEl = (<ElementRef_>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<string | any[]>): RenderComponentType {
return new RenderComponentType(`${this._appId}-${this._nextCompTypeId++}`, templateUrl,
slotCount, encapsulation, styles);
}
/** @internal */
renderComponent(renderComponentType: RenderComponentType): Renderer {
return this._renderer.renderComponent(renderComponentType);
}
}

View File

@ -11,6 +11,32 @@ import {BaseException} from 'angular2/src/facade/exceptions';
import {AppElement} from './element'; import {AppElement} from './element';
import {ExpressionChangedAfterItHasBeenCheckedException} from './exceptions'; import {ExpressionChangedAfterItHasBeenCheckedException} from './exceptions';
import {devModeEqual} from 'angular2/src/core/change_detection/change_detection'; 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<string | any[]>): 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[] { export function flattenNestedViewRenderNodes(nodes: any[]): any[] {
return _flattenNestedViewRenderNodes(nodes, []); return _flattenNestedViewRenderNodes(nodes, []);

View File

@ -145,8 +145,9 @@ class Attribute extends AttributeMetadata {
*/ */
@Deprecated("Use ContentChildren/ContentChild instead") @Deprecated("Use ContentChildren/ContentChild instead")
class Query extends QueryMetadata { class Query extends QueryMetadata {
const Query(dynamic /*Type | string*/ selector, {bool descendants: false}) const Query(dynamic /*Type | string*/ selector,
: super(selector, descendants: descendants); {bool descendants: false, dynamic read: null})
: super(selector, descendants: descendants, read: read);
} }
/** /**
@ -154,15 +155,15 @@ class Query extends QueryMetadata {
*/ */
class ContentChildren extends ContentChildrenMetadata { class ContentChildren extends ContentChildrenMetadata {
const ContentChildren(dynamic /*Type | string*/ selector, const ContentChildren(dynamic /*Type | string*/ selector,
{bool descendants: false}) {bool descendants: false, dynamic read: null})
: super(selector, descendants: descendants); : super(selector, descendants: descendants, read: read);
} }
/** /**
* See: [ContentChildMetadata] for docs. * See: [ContentChildMetadata] for docs.
*/ */
class ContentChild extends ContentChildMetadata { 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") @Deprecated("Use ViewChildren/ViewChild instead")
class ViewQuery extends ViewQueryMetadata { class ViewQuery extends ViewQueryMetadata {
const ViewQuery(dynamic /*Type | string*/ selector) const ViewQuery(dynamic /*Type | string*/ selector, {dynamic read: null})
: super(selector, descendants: true); : super(selector, descendants: true, read: read);
} }
/** /**
* See: [ViewChildrenMetadata] for docs. * See: [ViewChildrenMetadata] for docs.
*/ */
class ViewChildren extends ViewChildrenMetadata { 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. * See: [ViewChildMetadata] for docs.
*/ */
class ViewChild extends ViewChildMetadata { 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);
} }
/** /**

View File

@ -402,40 +402,43 @@ export interface AttributeMetadataFactory {
* ``` * ```
*/ */
export interface QueryMetadataFactory { export interface QueryMetadataFactory {
(selector: Type | string, {descendants}?: {descendants?: boolean}): ParameterDecorator; (selector: Type | string,
new (selector: Type | string, {descendants}?: {descendants?: boolean}): QueryMetadata; {descendants, read}?: {descendants?: boolean, read?: any}): ParameterDecorator;
new (selector: Type | string,
{descendants, read}?: {descendants?: boolean, read?: any}): QueryMetadata;
} }
/** /**
* Factory for {@link ContentChildren}. * Factory for {@link ContentChildren}.
*/ */
export interface ContentChildrenMetadataFactory { export interface ContentChildrenMetadataFactory {
(selector: Type | string, {descendants}?: {descendants?: boolean}): any; (selector: Type | string, {descendants, read}?: {descendants?: boolean, read?: any}): any;
new (selector: Type | string, {descendants}?: {descendants?: boolean}): ContentChildrenMetadata; new (selector: Type | string,
{descendants, read}?: {descendants?: boolean, read?: any}): ContentChildrenMetadata;
} }
/** /**
* Factory for {@link ContentChild}. * Factory for {@link ContentChild}.
*/ */
export interface ContentChildMetadataFactory { export interface ContentChildMetadataFactory {
(selector: Type | string): any; (selector: Type | string, {read}?: {read?: any}): any;
new (selector: Type | string): ContentChildMetadataFactory; new (selector: Type | string, {read}?: {read?: any}): ContentChildMetadataFactory;
} }
/** /**
* Factory for {@link ViewChildren}. * Factory for {@link ViewChildren}.
*/ */
export interface ViewChildrenMetadataFactory { export interface ViewChildrenMetadataFactory {
(selector: Type | string): any; (selector: Type | string, {read}?: {read?: any}): any;
new (selector: Type | string): ViewChildrenMetadata; new (selector: Type | string, {read}?: {read?: any}): ViewChildrenMetadata;
} }
/** /**
* Factory for {@link ViewChild}. * Factory for {@link ViewChild}.
*/ */
export interface ViewChildMetadataFactory { export interface ViewChildMetadataFactory {
(selector: Type | string): any; (selector: Type | string, {read}?: {read?: any}): any;
new (selector: Type | string): ViewChildMetadataFactory; new (selector: Type | string, {read}?: {read?: any}): ViewChildMetadataFactory;
} }

View File

@ -149,12 +149,18 @@ export class QueryMetadata extends DependencyMetadata {
*/ */
descendants: boolean; descendants: boolean;
first: boolean; first: boolean;
/**
* The DI token to read from an element that matches the selector.
*/
read: any;
constructor(private _selector: Type | string, 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(); super();
this.descendants = descendants; this.descendants = descendants;
this.first = first; this.first = first;
this.read = read;
} }
/** /**
@ -204,8 +210,9 @@ export class QueryMetadata extends DependencyMetadata {
*/ */
@CONST() @CONST()
export class ContentChildrenMetadata extends QueryMetadata { export class ContentChildrenMetadata extends QueryMetadata {
constructor(_selector: Type | string, {descendants = false}: {descendants?: boolean} = {}) { constructor(_selector: Type | string,
super(_selector, {descendants: descendants}); {descendants = false, read = null}: {descendants?: boolean, read?: any} = {}) {
super(_selector, {descendants: descendants, read: read});
} }
} }
@ -232,7 +239,9 @@ export class ContentChildrenMetadata extends QueryMetadata {
*/ */
@CONST() @CONST()
export class ContentChildMetadata extends QueryMetadata { 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() @CONST()
export class ViewQueryMetadata extends QueryMetadata { export class ViewQueryMetadata extends QueryMetadata {
constructor(_selector: Type | string, constructor(_selector: Type | string,
{descendants = false, first = false}: {descendants?: boolean, first?: boolean} = {}) { {descendants = false, first = false,
super(_selector, {descendants: descendants, first: first}); 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() @CONST()
export class ViewChildrenMetadata extends ViewQueryMetadata { 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() @CONST()
export class ViewChildMetadata extends ViewQueryMetadata { 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});
}
} }

View File

@ -186,8 +186,8 @@ export class RouterLinkTransform implements TemplateAstVisitor {
let updatedInputs = ast.inputs.map(c => c.visit(this, context)); let updatedInputs = ast.inputs.map(c => c.visit(this, context));
let updatedDirectives = ast.directives.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, return new ElementAst(ast.name, ast.attrs, updatedInputs, ast.outputs, ast.exportAsVars,
updatedDirectives, ast.providers, updatedChildren, ast.ngContentIndex, updatedDirectives, ast.providers, ast.hasViewContainer, updatedChildren,
ast.sourceSpan); ast.ngContentIndex, ast.sourceSpan);
} }
visitVariable(ast: any, context: any): any { return ast; } visitVariable(ast: any, context: any): any { return ast; }

View File

@ -7,7 +7,7 @@ import {
Attribute, Attribute,
DynamicComponentLoader, DynamicComponentLoader,
ComponentRef, ComponentRef,
ElementRef, ViewContainerRef,
Injector, Injector,
provide, provide,
Dependency, Dependency,
@ -40,7 +40,7 @@ export class RouterOutlet implements OnDestroy {
@Output('activate') public activateEvents = new EventEmitter<any>(); @Output('activate') public activateEvents = new EventEmitter<any>();
constructor(private _elementRef: ElementRef, private _loader: DynamicComponentLoader, constructor(private _viewContainerRef: ViewContainerRef, private _loader: DynamicComponentLoader,
private _parentRouter: routerMod.Router, @Attribute('name') nameAttr: string) { private _parentRouter: routerMod.Router, @Attribute('name') nameAttr: string) {
if (isPresent(nameAttr)) { if (isPresent(nameAttr)) {
this.name = nameAttr; this.name = nameAttr;
@ -66,7 +66,7 @@ export class RouterOutlet implements OnDestroy {
provide(routerMod.Router, {useValue: childRouter}) provide(routerMod.Router, {useValue: childRouter})
]); ]);
this._componentRef = this._componentRef =
this._loader.loadNextToLocation(componentType, this._elementRef, providers); this._loader.loadNextToLocation(componentType, this._viewContainerRef, providers);
return this._componentRef.then((componentRef) => { return this._componentRef.then((componentRef) => {
this.activateEvents.emit(componentRef.instance); this.activateEvents.emit(componentRef.instance);
if (hasLifecycleHook(hookMod.routerOnActivate, componentType)) { if (hasLifecycleHook(hookMod.routerOnActivate, componentType)) {

View File

@ -1,4 +1,3 @@
export const NG2_APP_VIEW_MANAGER = 'ng2.AppViewManager';
export const NG2_COMPILER = 'ng2.Compiler'; export const NG2_COMPILER = 'ng2.Compiler';
export const NG2_INJECTOR = 'ng2.Injector'; export const NG2_INJECTOR = 'ng2.Injector';
export const NG2_COMPONENT_FACTORY_REF_MAP = 'ng2.ComponentFactoryRefMap'; export const NG2_COMPONENT_FACTORY_REF_MAP = 'ng2.ComponentFactoryRefMap';

View File

@ -1,6 +1,5 @@
import { import {
provide, provide,
AppViewManager,
ChangeDetectorRef, ChangeDetectorRef,
Injector, Injector,
OnChanges, OnChanges,
@ -30,8 +29,7 @@ export class DowngradeNg2ComponentAdapter {
constructor(private id: string, private info: ComponentInfo, constructor(private id: string, private info: ComponentInfo,
private element: angular.IAugmentedJQuery, private attrs: angular.IAttributes, private element: angular.IAugmentedJQuery, private attrs: angular.IAttributes,
private scope: angular.IScope, private parentInjector: Injector, private scope: angular.IScope, private parentInjector: Injector,
private parse: angular.IParseService, private viewManager: AppViewManager, private parse: angular.IParseService, private componentFactory: ComponentFactory) {
private componentFactory: ComponentFactory) {
(<any>this.element[0]).id = id; (<any>this.element[0]).id = id;
this.componentScope = scope.$new(); this.componentScope = scope.$new();
this.childNodes = <Node[]><any>element.contents(); this.childNodes = <Node[]><any>element.contents();

View File

@ -2,7 +2,6 @@ import {
provide, provide,
platform, platform,
ApplicationRef, ApplicationRef,
AppViewManager,
ComponentResolver, ComponentResolver,
Injector, Injector,
NgZone, NgZone,
@ -26,7 +25,6 @@ import {
NG1_ROOT_SCOPE, NG1_ROOT_SCOPE,
NG1_SCOPE, NG1_SCOPE,
NG1_TESTABILITY, NG1_TESTABILITY,
NG2_APP_VIEW_MANAGER,
NG2_COMPILER, NG2_COMPILER,
NG2_INJECTOR, NG2_INJECTOR,
NG2_COMPONENT_FACTORY_REF_MAP, NG2_COMPONENT_FACTORY_REF_MAP,
@ -318,7 +316,6 @@ export class UpgradeAdapter {
.value(NG2_ZONE, ngZone) .value(NG2_ZONE, ngZone)
.value(NG2_COMPILER, compiler) .value(NG2_COMPILER, compiler)
.value(NG2_COMPONENT_FACTORY_REF_MAP, componentFactoryRefMap) .value(NG2_COMPONENT_FACTORY_REF_MAP, componentFactoryRefMap)
.value(NG2_APP_VIEW_MANAGER, injector.get(AppViewManager))
.config([ .config([
'$provide', '$provide',
(provide) => { (provide) => {
@ -542,10 +539,8 @@ interface ComponentFactoryRefMap {
} }
function ng1ComponentDirective(info: ComponentInfo, idPrefix: string): Function { function ng1ComponentDirective(info: ComponentInfo, idPrefix: string): Function {
(<any>directiveFactory).$inject = (<any>directiveFactory).$inject = [NG2_COMPONENT_FACTORY_REF_MAP, NG1_PARSE];
[NG2_COMPONENT_FACTORY_REF_MAP, NG2_APP_VIEW_MANAGER, NG1_PARSE];
function directiveFactory(componentFactoryRefMap: ComponentFactoryRefMap, function directiveFactory(componentFactoryRefMap: ComponentFactoryRefMap,
viewManager: AppViewManager,
parse: angular.IParseService): angular.IDirective { parse: angular.IParseService): angular.IDirective {
var componentFactory: ComponentFactory = componentFactoryRefMap[info.selector]; var componentFactory: ComponentFactory = componentFactoryRefMap[info.selector];
if (!componentFactory) throw new Error('Expecting ComponentFactory for: ' + 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, post: (scope: angular.IScope, element: angular.IAugmentedJQuery, attrs: angular.IAttributes,
parentInjector: any, transclude: angular.ITranscludeFunction): void => { parentInjector: any, transclude: angular.ITranscludeFunction): void => {
var domElement = <any>element[0]; var domElement = <any>element[0];
var facade = new DowngradeNg2ComponentAdapter(idPrefix + (idCount++), info, element, var facade =
attrs, scope, <Injector>parentInjector, new DowngradeNg2ComponentAdapter(idPrefix + (idCount++), info, element, attrs, scope,
parse, viewManager, componentFactory); <Injector>parentInjector, parse, componentFactory);
facade.setupInputs(); facade.setupInputs();
facade.bootstrapNg2(); facade.bootstrapNg2();
facade.projectContent(); facade.projectContent();

View File

@ -1506,7 +1506,8 @@ class FooAstTransformer implements TemplateAstVisitor {
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { throw 'not implemented'; } visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any { throw 'not implemented'; }
visitElement(ast: ElementAst, context: any): any { visitElement(ast: ElementAst, context: any): any {
if (ast.name != 'div') return ast; 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'; } visitVariable(ast: VariableAst, context: any): any { throw 'not implemented'; }
visitEvent(ast: BoundEventAst, 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 { class BarAstTransformer extends FooAstTransformer {
visitElement(ast: ElementAst, context: any): any { visitElement(ast: ElementAst, context: any): any {
if (ast.name != 'foo') return ast; if (ast.name != 'foo') return ast;
return new ElementAst('bar', [], [], [], [], [], [], [], ast.ngContentIndex, ast.sourceSpan); return new ElementAst('bar', [], [], [], [], [], [], false, [], ast.ngContentIndex,
ast.sourceSpan);
} }
} }

View File

@ -17,11 +17,11 @@ import {
} from 'angular2/testing_internal'; } from 'angular2/testing_internal';
import {Predicate} from 'angular2/src/facade/collection'; 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 {NgIf} from 'angular2/common';
import {Component, ViewMetadata} from 'angular2/src/core/metadata'; import {Component, ViewMetadata} from 'angular2/src/core/metadata';
import {DynamicComponentLoader} from 'angular2/src/core/linker/dynamic_component_loader'; 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 {DOCUMENT} from 'angular2/src/platform/dom/dom_tokens';
import {DOM} from 'angular2/src/platform/dom/dom_adapter'; import {DOM} from 'angular2/src/platform/dom/dom_adapter';
import {BaseException} from 'angular2/src/facade/exceptions'; import {BaseException} from 'angular2/src/facade/exceptions';
@ -29,266 +29,112 @@ import {PromiseWrapper} from 'angular2/src/facade/promise';
export function main() { export function main() {
describe('DynamicComponentLoader', function() { describe('DynamicComponentLoader', function() {
describe("loading into a location", () => { describe("loading next to a location", () => {
it('should work', it('should work',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter], inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => { (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
tcb.overrideView( tcb.createAsync(MyComp).then((tc) => {
MyComp, tc.detectChanges();
new ViewMetadata( loader.loadNextToLocation(DynamicallyLoaded,
{template: '<location #loc></location>', directives: [Location]})) tc.componentInstance.viewContainerRef)
.createAsync(MyComp) .then(ref => {
.then((tc) => { expect(tc.debugElement.nativeElement).toHaveText('DynamicallyLoaded;');
loader.loadIntoLocation(DynamicallyLoaded, tc.elementRef, 'loc')
.then(ref => { async.done();
expect(tc.debugElement.nativeElement) });
.toHaveText("Location;DynamicallyLoaded;"); });
async.done();
});
});
})); }));
it('should return a disposable component ref', it('should return a disposable component ref',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(
MyComp,
new ViewMetadata(
{template: '<location #loc></location>', 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: '<child-cmp *ngIf="ctxBoolProp"></child-cmp>',
directives: [NgIf, ChildComp]
}))
.overrideView(
ChildComp,
new ViewMetadata(
{template: '<location #loc></location>', 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( inject(
[DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter], [DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => { (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
tcb.overrideView( tcb.createAsync(MyComp).then((tc) => {
MyComp, new ViewMetadata( tc.detectChanges();
{template: '<location #loc></location>', directives: [Location]})) loader.loadNextToLocation(DynamicallyLoaded, tc.componentInstance.viewContainerRef)
.createAsync(MyComp) .then(ref => {
.then((tc) => { loader.loadNextToLocation(DynamicallyLoaded2,
loader.loadIntoLocation(DynamicallyLoadedWithHostProps, tc.elementRef, 'loc') tc.componentInstance.viewContainerRef)
.then(ref => { .then(ref2 => {
ref.instance.id = "new value"; expect(tc.debugElement.nativeElement)
.toHaveText("DynamicallyLoaded;DynamicallyLoaded2;");
tc.detectChanges(); ref2.destroy();
var newlyInsertedElement = expect(tc.debugElement.nativeElement).toHaveText("DynamicallyLoaded;");
DOM.childNodes(tc.debugElement.nativeElement)[1];
expect((<HTMLElement>newlyInsertedElement).id).toEqual("new value"); async.done();
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((<HTMLElement>newlyInsertedElement).id).toEqual("new value");
async.done();
});
});
}));
it('should leave the view tree in a consistent state if hydration fails', it('should leave the view tree in a consistent state if hydration fails',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter], inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => { (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, new ViewMetadata({ tcb.createAsync(MyComp).then((tc: ComponentFixture) => {
template: '<div><location #loc></location></div>', tc.detectChanges();
directives: [Location] PromiseWrapper.catchError(
})) loader.loadNextToLocation(DynamicallyLoadedThrows,
.createAsync(MyComp) tc.componentInstance.viewContainerRef),
.then((tc: ComponentFixture) => { (error) => {
PromiseWrapper.catchError( expect(error.message).toContain("ThrownInConstructor");
loader.loadIntoLocation(DynamicallyLoadedThrows, tc.elementRef, 'loc'), expect(() => tc.detectChanges()).not.toThrow();
(error) => { async.done();
expect(error.message).toContain("ThrownInConstructor"); return null;
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: '<location #loc></location>', directives: [Location]}))
.createAsync(MyComp)
.then((tc) => {
expect(() => loader.loadIntoLocation(DynamicallyLoadedWithHostProps,
tc.elementRef, 'someUnknownVariable'))
.toThrowError('Could not find variable someUnknownVariable');
async.done();
});
})); }));
it('should allow to pass projectable nodes', it('should allow to pass projectable nodes',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter], inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => { (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, tcb.createAsync(MyComp).then((tc) => {
new ViewMetadata({template: '<div #loc></div>', directives: []})) tc.detectChanges();
.createAsync(MyComp) loader.loadNextToLocation(DynamicallyLoadedWithNgContent,
.then((tc) => { tc.componentInstance.viewContainerRef, null,
loader.loadIntoLocation(DynamicallyLoadedWithNgContent, tc.elementRef, [[DOM.createTextNode('hello')]])
'loc', null, [[DOM.createTextNode('hello')]]) .then(ref => {
.then(ref => { tc.detectChanges();
tc.detectChanges(); var newlyInsertedElement = tc.debugElement.childNodes[1].nativeNode;
expect(tc.nativeElement).toHaveText('dynamic(hello)'); expect(newlyInsertedElement).toHaveText('dynamic(hello)');
async.done(); async.done();
}); });
}); });
})); }));
it('should not throw if not enough projectable nodes are passed in', it('should not throw if not enough projectable nodes are passed in',
inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter], inject([DynamicComponentLoader, TestComponentBuilder, AsyncTestCompleter],
(loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => { (loader: DynamicComponentLoader, tcb: TestComponentBuilder, async) => {
tcb.overrideView(MyComp, tcb.createAsync(MyComp).then((tc) => {
new ViewMetadata({template: '<div #loc></div>', directives: []})) tc.detectChanges();
.createAsync(MyComp) loader.loadNextToLocation(DynamicallyLoadedWithNgContent,
.then((tc) => { tc.componentInstance.viewContainerRef, null, [])
loader.loadIntoLocation(DynamicallyLoadedWithNgContent, tc.elementRef, .then((_) => { async.done(); });
'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: '<div><location #loc></location></div>',
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: '<div><location #loc></location></div>',
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: '<div><location #loc></location></div>',
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((<HTMLElement>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();
});
});
})); }));
}); });
@ -362,27 +208,6 @@ class ChildComp {
constructor(public elementRef: ElementRef) { this.ctxProp = 'hello'; } 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;"}) @Component({selector: 'dummy', template: "DynamicallyLoaded;"})
class DynamicallyLoaded { class DynamicallyLoaded {
} }
@ -410,16 +235,11 @@ class DynamicallyLoadedWithNgContent {
constructor() { this.id = "default"; } constructor() { this.id = "default"; }
} }
@Component({selector: 'location', template: "Location;"}) @Component({selector: 'my-comp', directives: [], template: '<div #loc></div>'})
class Location {
elementRef: ElementRef;
constructor(elementRef: ElementRef) { this.elementRef = elementRef; }
}
@Component({selector: 'my-comp', directives: []})
class MyComp { class MyComp {
ctxBoolProp: boolean; ctxBoolProp: boolean;
@ViewChild('loc', {read: ViewContainerRef}) viewContainerRef: ViewContainerRef;
constructor() { this.ctxBoolProp = false; } constructor() { this.ctxBoolProp = false; }
} }

View File

@ -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 =
'<needs-content-children-read #q text="ca"><div #q text="cb"></div></needs-content-children-read>';
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 =
'<needs-content-child-read><div #q text="ca"></div></needs-content-child-read>';
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 = '<needs-view-child-read></needs-view-child-read>';
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 = '<needs-view-children-read></needs-view-children-read>';
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 =
'<needs-viewcontainer-read><template>hello</template></needs-viewcontainer-read>';
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", () => { describe("changes", () => {
it('should notify query on change', it('should notify query on change',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => { 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<TextDirective>;
@ContentChildren('nonExisting', {read: TextDirective}) nonExistingVar: QueryList<TextDirective>;
}
@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: '<div #q text="va"></div><div #q text="vb"></div>',
directives: [TextDirective]
})
class NeedsViewChildrenWithRead {
@ViewChildren('q', {read: TextDirective}) textDirChildren: QueryList<TextDirective>;
@ViewChildren('nonExisting', {read: TextDirective}) nonExistingVar: QueryList<TextDirective>;
}
@Component({
selector: 'needs-view-child-read',
template: '<div #q text="va"></div>',
directives: [TextDirective]
})
class NeedsViewChildWithRead {
@ViewChild('q', {read: TextDirective}) textDirChild: TextDirective;
@ViewChild('nonExisting', {read: TextDirective}) nonExistingVar: TextDirective;
}
@Component({selector: 'needs-viewcontainer-read', template: '<div #q></div>'})
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({ @Component({
selector: 'my-comp', selector: 'my-comp',
directives: [ directives: [
@ -946,7 +1080,12 @@ class NeedsTpl {
InertDirective, InertDirective,
NgIf, NgIf,
NgFor, NgFor,
NeedsFourQueries NeedsFourQueries,
NeedsContentChildrenWithRead,
NeedsContentChildWithRead,
NeedsViewChildrenWithRead,
NeedsViewChildWithRead,
NeedsViewContainerWithRead
], ],
template: '' template: ''
}) })

View File

@ -604,7 +604,7 @@ export function main() {
it("should inject TemplateRef", fakeAsync(() => { it("should inject TemplateRef", fakeAsync(() => {
var el = createComp('<template needsViewContainerRef needsTemplateRef></template>', tcb); var el = createComp('<template needsViewContainerRef needsTemplateRef></template>', tcb);
expect(el.childNodes[0].inject(NeedsTemplateRef).templateRef.elementRef) 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(() => { it("should throw if there is no TemplateRef", fakeAsync(() => {

View File

@ -145,7 +145,6 @@ var NG_CORE = [
'APP_ID', 'APP_ID',
'AngularEntrypoint:dart', 'AngularEntrypoint:dart',
'AbstractProviderError', 'AbstractProviderError',
'AppViewManager',
'ApplicationRef', 'ApplicationRef',
'APPLICATION_COMMON_PROVIDERS', 'APPLICATION_COMMON_PROVIDERS',
'Attribute', 'Attribute',

View File

@ -1,4 +1,4 @@
import {Component, ComponentRef} from 'angular2/core'; import {Component, ComponentRef, ViewContainerRef, ViewChild} from 'angular2/core';
import { import {
AsyncRoute, AsyncRoute,
Route, Route,
@ -11,7 +11,6 @@ import {
import {PromiseWrapper} from 'angular2/src/facade/async'; import {PromiseWrapper} from 'angular2/src/facade/async';
import {isPresent} from 'angular2/src/facade/lang'; import {isPresent} from 'angular2/src/facade/lang';
import {DynamicComponentLoader} from 'angular2/src/core/linker/dynamic_component_loader'; 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}}`}) @Component({selector: 'goodbye-cmp', template: `{{farewell}}`})
export class GoodbyeCmp { export class GoodbyeCmp {
@ -144,16 +143,17 @@ export class RedirectToParentCmp {
@RouteConfig([new Route({path: '/', component: HelloCmp})]) @RouteConfig([new Route({path: '/', component: HelloCmp})])
export class DynamicLoaderCmp { export class DynamicLoaderCmp {
private _componentRef: ComponentRef = null; private _componentRef: ComponentRef = null;
constructor(private _dynamicComponentLoader: DynamicComponentLoader, @ViewChild('viewport', {read: ViewContainerRef}) private _viewport: ViewContainerRef;
private _elementRef: ElementRef) {}
constructor(private _dynamicComponentLoader: DynamicComponentLoader) {}
onSomeAction(): Promise<any> { onSomeAction(): Promise<any> {
if (isPresent(this._componentRef)) { if (isPresent(this._componentRef)) {
this._componentRef.destroy(); this._componentRef.destroy();
this._componentRef = null; this._componentRef = null;
} }
return this._dynamicComponentLoader.loadIntoLocation(DynamicallyLoadedComponent, return this._dynamicComponentLoader.loadNextToLocation(DynamicallyLoadedComponent,
this._elementRef, 'viewport') this._viewport)
.then((cmp) => { this._componentRef = cmp; }); .then((cmp) => { this._componentRef = cmp; });
} }
} }

View File

@ -21,7 +21,8 @@ import {
ViewMetadata, ViewMetadata,
Component, Component,
Injectable, Injectable,
ElementRef ElementRef,
ComponentRef
} from 'angular2/core'; } from 'angular2/core';
import {NgIf} from 'angular2/common'; import {NgIf} from 'angular2/common';
import {WebWorkerRootRenderer} from "angular2/src/web_workers/worker/renderer"; import {WebWorkerRootRenderer} from "angular2/src/web_workers/worker/renderer";
@ -119,8 +120,8 @@ export function main() {
return uiRenderStore.deserialize(id); return uiRenderStore.deserialize(id);
} }
function getRenderer(elementRef: ElementRef) { function getRenderer(componentRef: ComponentRef) {
return (<any>elementRef).internalElement.parentView.renderer; return (<any>componentRef.hostView).internalView.renderer;
} }
it('should update text nodes', it('should update text nodes',
@ -145,8 +146,8 @@ export function main() {
{template: '<input [title]="y" style="position:absolute">'})) {template: '<input [title]="y" style="position:absolute">'}))
.createAsync(MyComp) .createAsync(MyComp)
.then((fixture) => { .then((fixture) => {
var checkSetters = (componentElRef, workerEl) => { var checkSetters = (componentRef, workerEl) => {
var renderer = getRenderer(componentElRef); var renderer = getRenderer(componentRef);
var el = getRenderElement(workerEl); var el = getRenderElement(workerEl);
renderer.setElementProperty(workerEl, 'tabIndex', 1); renderer.setElementProperty(workerEl, 'tabIndex', 1);
expect((<HTMLInputElement>el).tabIndex).toEqual(1); expect((<HTMLInputElement>el).tabIndex).toEqual(1);
@ -166,9 +167,9 @@ export function main() {
}; };
// root element // root element
checkSetters(fixture.elementRef, fixture.debugElement.nativeElement); checkSetters(fixture.componentRef, fixture.debugElement.nativeElement);
// nested elements // nested elements
checkSetters(fixture.elementRef, fixture.debugElement.children[0].nativeElement); checkSetters(fixture.componentRef, fixture.debugElement.children[0].nativeElement);
async.done(); async.done();
}); });
@ -220,7 +221,7 @@ export function main() {
.createAsync(MyComp) .createAsync(MyComp)
.then((fixture) => { .then((fixture) => {
var el = fixture.debugElement.children[0]; var el = fixture.debugElement.children[0];
getRenderer(fixture.elementRef) getRenderer(fixture.componentRef)
.invokeElementMethod(el.nativeElement, 'setAttribute', ['a', 'b']); .invokeElementMethod(el.nativeElement, 'setAttribute', ['a', 'b']);
expect(DOM.getAttribute(getRenderElement(el.nativeElement), 'a')).toEqual('b'); expect(DOM.getAttribute(getRenderElement(el.nativeElement), 'a')).toEqual('b');

View File

@ -1,5 +1,5 @@
import {bootstrap} from 'angular2/platform/browser'; 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 {NgIf, NgFor} from 'angular2/common';
import {ApplicationRef} from 'angular2/src/core/application_ref'; import {ApplicationRef} from 'angular2/src/core/application_ref';
import {ListWrapper} from 'angular2/src/facade/collection'; import {ListWrapper} from 'angular2/src/facade/collection';
@ -53,7 +53,7 @@ class DummyDirective {
@Directive({selector: 'dynamic-dummy'}) @Directive({selector: 'dynamic-dummy'})
class DynamicDummy { class DynamicDummy {
constructor(loader: DynamicComponentLoader, location: ElementRef) { constructor(loader: DynamicComponentLoader, location: ViewContainerRef) {
loader.loadNextToLocation(DummyComponent, location); loader.loadNextToLocation(DummyComponent, location);
} }
} }

View File

@ -28,9 +28,6 @@ const CORE = [
'AfterViewChecked.ngAfterViewChecked():any', 'AfterViewChecked.ngAfterViewChecked():any',
'AfterViewInit', 'AfterViewInit',
'AfterViewInit.ngAfterViewInit():any', 'AfterViewInit.ngAfterViewInit():any',
'AppViewManager',
'AppViewManager.getNamedElementInComponentView(hostLocation:ElementRef, variableName:string):ElementRef',
'AppViewManager.getViewContainer(location:ElementRef):ViewContainerRef',
'ApplicationRef', 'ApplicationRef',
'ApplicationRef.bootstrap(componentType:Type, providers:Array<Type|Provider|any[]>):Promise<ComponentRef>', 'ApplicationRef.bootstrap(componentType:Type, providers:Array<Type|Provider|any[]>):Promise<ComponentRef>',
'ApplicationRef.componentTypes:Type[]', 'ApplicationRef.componentTypes:Type[]',
@ -104,10 +101,10 @@ const CORE = [
'ConcreteType', 'ConcreteType',
'ContentChildMetadataFactory', 'ContentChildMetadataFactory',
'ContentChildMetadata', 'ContentChildMetadata',
'ContentChildMetadata.constructor(_selector:Type|string)', 'ContentChildMetadata.constructor(_selector:Type|string, {read=null}:{read?:any})',
'ContentChildrenMetadataFactory', 'ContentChildrenMetadataFactory',
'ContentChildrenMetadata', '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',
'CyclicDependencyError.constructor(injector:Injector, key:Key)', 'CyclicDependencyError.constructor(injector:Injector, key:Key)',
'DebugNode', 'DebugNode',
@ -161,10 +158,10 @@ const CORE = [
'DoCheck.ngDoCheck():any', 'DoCheck.ngDoCheck():any',
'DynamicComponentLoader', 'DynamicComponentLoader',
'DynamicComponentLoader.loadAsRoot(type:Type, overrideSelectorOrNode:string, injector:Injector, onDispose:() => void, projectableNodes:any[][]):Promise<ComponentRef>', 'DynamicComponentLoader.loadAsRoot(type:Type, overrideSelectorOrNode:string, injector:Injector, onDispose:() => void, projectableNodes:any[][]):Promise<ComponentRef>',
'DynamicComponentLoader.loadIntoLocation(type:Type, hostLocation:ElementRef, anchorName:string, providers:ResolvedProvider[], projectableNodes:any[][]):Promise<ComponentRef>', 'DynamicComponentLoader.loadNextToLocation(type:Type, location:ViewContainerRef, providers:ResolvedProvider[], projectableNodes:any[][]):Promise<ComponentRef>',
'DynamicComponentLoader.loadNextToLocation(type:Type, location:ElementRef, providers:ResolvedProvider[], projectableNodes:any[][]):Promise<ComponentRef>',
'ElementRef', 'ElementRef',
'ElementRef.nativeElement:any', 'ElementRef.nativeElement:any',
'ElementRef.constructor(nativeElement:any)',
'EmbeddedViewRef', 'EmbeddedViewRef',
'EmbeddedViewRef.hasLocal(variableName:string):boolean', 'EmbeddedViewRef.hasLocal(variableName:string):boolean',
'EmbeddedViewRef.rootNodes:any[]', 'EmbeddedViewRef.rootNodes:any[]',
@ -344,7 +341,8 @@ const CORE = [
'QueryList.toString():string', 'QueryList.toString():string',
'QueryList<T>', 'QueryList<T>',
'QueryMetadata', '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.descendants:boolean',
'QueryMetadata.first:boolean', 'QueryMetadata.first:boolean',
'QueryMetadata.isVarBindingQuery:boolean', 'QueryMetadata.isVarBindingQuery:boolean',
@ -438,10 +436,10 @@ const CORE = [
'TypeDecorator.annotations:any[]', 'TypeDecorator.annotations:any[]',
'ViewChildMetadataFactory', 'ViewChildMetadataFactory',
'ViewChildMetadata', 'ViewChildMetadata',
'ViewChildMetadata.constructor(_selector:Type|string)', 'ViewChildMetadata.constructor(_selector:Type|string, {read=null}:{read?:any})',
'ViewChildrenMetadataFactory', 'ViewChildrenMetadataFactory',
'ViewChildrenMetadata', 'ViewChildrenMetadata',
'ViewChildrenMetadata.constructor(_selector:Type|string)', 'ViewChildrenMetadata.constructor(_selector:Type|string, {read=null}:{read?:any})',
'ViewContainerRef', 'ViewContainerRef',
'ViewContainerRef.clear():void', 'ViewContainerRef.clear():void',
'ViewContainerRef.createEmbeddedView(templateRef:TemplateRef, index:number):EmbeddedViewRef', 'ViewContainerRef.createEmbeddedView(templateRef:TemplateRef, index:number):EmbeddedViewRef',
@ -470,7 +468,7 @@ const CORE = [
'ViewMetadata.template:string', 'ViewMetadata.template:string',
'ViewMetadata.templateUrl:string', 'ViewMetadata.templateUrl:string',
'ViewQueryMetadata', '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.isViewQuery:any',
'ViewQueryMetadata.toString():string', 'ViewQueryMetadata.toString():string',
'ViewRef', 'ViewRef',
@ -844,12 +842,12 @@ const COMPILER =
'DirectiveAst.constructor(directive:CompileDirectiveMetadata, inputs:BoundDirectivePropertyAst[], hostProperties:BoundElementPropertyAst[], hostEvents:BoundEventAst[], exportAsVars:VariableAst[], sourceSpan:ParseSourceSpan)', 'DirectiveAst.constructor(directive:CompileDirectiveMetadata, inputs:BoundDirectivePropertyAst[], hostProperties:BoundElementPropertyAst[], hostEvents:BoundEventAst[], exportAsVars:VariableAst[], sourceSpan:ParseSourceSpan)',
'DirectiveAst.visit(visitor:TemplateAstVisitor, context:any):any', 'DirectiveAst.visit(visitor:TemplateAstVisitor, context:any):any',
'ElementAst', '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.getComponent():CompileDirectiveMetadata',
'ElementAst.isBound():boolean', 'ElementAst.isBound():boolean',
'ElementAst.visit(visitor:TemplateAstVisitor, context:any):any', 'ElementAst.visit(visitor:TemplateAstVisitor, context:any):any',
'EmbeddedTemplateAst', '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', 'EmbeddedTemplateAst.visit(visitor:TemplateAstVisitor, context:any):any',
'NgContentAst', 'NgContentAst',
'NgContentAst.constructor(index:number, ngContentIndex:number, sourceSpan:ParseSourceSpan)', 'NgContentAst.constructor(index:number, ngContentIndex:number, sourceSpan:ParseSourceSpan)',
@ -958,7 +956,8 @@ const COMPILER =
'CompileProviderMetadata.useFactory:CompileFactoryMetadata', 'CompileProviderMetadata.useFactory:CompileFactoryMetadata',
'CompileProviderMetadata.useValue:any', 'CompileProviderMetadata.useValue:any',
'CompileQueryMetadata', 'CompileQueryMetadata',
'CompileQueryMetadata.constructor({selectors,descendants,first,propertyName}:{selectors?:Array<CompileTokenMetadata>, descendants?:boolean, first?:boolean, propertyName?:string})', 'CompileQueryMetadata.constructor({selectors,descendants,first,propertyName,read}:{selectors?:Array<CompileTokenMetadata>, descendants?:boolean, first?:boolean, propertyName?:string, read?:CompileTokenMetadata})',
'CompileQueryMetadata.read:CompileTokenMetadata',
'CompileQueryMetadata.descendants:boolean', 'CompileQueryMetadata.descendants:boolean',
'CompileQueryMetadata.first:boolean', 'CompileQueryMetadata.first:boolean',
'CompileQueryMetadata.fromJson(data:{[key:string]:any}):CompileQueryMetadata', 'CompileQueryMetadata.fromJson(data:{[key:string]:any}):CompileQueryMetadata',