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:
@ -13,7 +13,12 @@ import {
|
||||
isArray
|
||||
} from 'angular2/src/facade/lang';
|
||||
import {unimplemented, BaseException} from 'angular2/src/facade/exceptions';
|
||||
import {StringMapWrapper, MapWrapper, SetWrapper} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
StringMapWrapper,
|
||||
MapWrapper,
|
||||
SetWrapper,
|
||||
ListWrapper
|
||||
} from 'angular2/src/facade/collection';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
CHANGE_DETECTION_STRATEGY_VALUES
|
||||
@ -414,17 +419,20 @@ export class CompileQueryMetadata {
|
||||
descendants: boolean;
|
||||
first: boolean;
|
||||
propertyName: string;
|
||||
read: CompileTokenMetadata;
|
||||
|
||||
constructor({selectors, descendants, first, propertyName}: {
|
||||
constructor({selectors, descendants, first, propertyName, read}: {
|
||||
selectors?: Array<CompileTokenMetadata>,
|
||||
descendants?: boolean,
|
||||
first?: boolean,
|
||||
propertyName?: string
|
||||
propertyName?: string,
|
||||
read?: CompileTokenMetadata
|
||||
} = {}) {
|
||||
this.selectors = selectors;
|
||||
this.descendants = normalizeBool(descendants);
|
||||
this.first = normalizeBool(first);
|
||||
this.propertyName = propertyName;
|
||||
this.read = read;
|
||||
}
|
||||
|
||||
static fromJson(data: {[key: string]: any}): CompileQueryMetadata {
|
||||
@ -432,7 +440,8 @@ export class CompileQueryMetadata {
|
||||
selectors: _arrayFromJson(data['selectors'], CompileTokenMetadata.fromJson),
|
||||
descendants: data['descendants'],
|
||||
first: data['first'],
|
||||
propertyName: data['propertyName']
|
||||
propertyName: data['propertyName'],
|
||||
read: _objFromJson(data['read'], CompileTokenMetadata.fromJson)
|
||||
});
|
||||
}
|
||||
|
||||
@ -441,7 +450,8 @@ export class CompileQueryMetadata {
|
||||
'selectors': _arrayToJson(this.selectors),
|
||||
'descendants': this.descendants,
|
||||
'first': this.first,
|
||||
'propertyName': this.propertyName
|
||||
'propertyName': this.propertyName,
|
||||
'read': _objToJson(this.read)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadat
|
||||
import {AppView} from 'angular2/src/core/linker/view';
|
||||
import {StaticNodeDebugInfo, DebugContext} from 'angular2/src/core/linker/debug_context';
|
||||
import {
|
||||
ViewUtils,
|
||||
flattenNestedViewRenderNodes,
|
||||
interpolate,
|
||||
checkBinding
|
||||
@ -15,7 +16,6 @@ import {
|
||||
ChangeDetectorState,
|
||||
ChangeDetectionStrategy
|
||||
} from 'angular2/src/core/change_detection/change_detection';
|
||||
import {AppViewManager_} from 'angular2/src/core/linker/view_manager';
|
||||
import {AppElement} from 'angular2/src/core/linker/element';
|
||||
import {ElementRef} from 'angular2/src/core/linker/element_ref';
|
||||
import {ViewContainerRef} from 'angular2/src/core/linker/view_container_ref';
|
||||
@ -34,7 +34,7 @@ var CD_MODULE_URL = 'asset:angular2/lib/src/core/change_detection/change_detecti
|
||||
// Reassign the imports to different variables so we can
|
||||
// define static variables with the name of the import.
|
||||
// (only needed for Dart).
|
||||
var impAppViewManager_ = AppViewManager_;
|
||||
var impViewUtils = ViewUtils;
|
||||
var impAppView = AppView;
|
||||
var impDebugContext = DebugContext;
|
||||
var impAppElement = AppElement;
|
||||
@ -61,10 +61,10 @@ var impInterpolate = interpolate;
|
||||
var impCheckBinding = checkBinding;
|
||||
|
||||
export class Identifiers {
|
||||
static AppViewManager_ = new CompileIdentifierMetadata({
|
||||
name: 'AppViewManager_',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/view_manager' + MODULE_SUFFIX,
|
||||
runtime: impAppViewManager_
|
||||
static ViewUtils = new CompileIdentifierMetadata({
|
||||
name: 'ViewUtils',
|
||||
moduleUrl: 'asset:angular2/lib/src/core/linker/view_utils' + MODULE_SUFFIX,
|
||||
runtime: impViewUtils
|
||||
});
|
||||
static AppView = new CompileIdentifierMetadata(
|
||||
{name: 'AppView', moduleUrl: APP_VIEW_MODULE_URL, runtime: impAppView});
|
||||
|
@ -65,28 +65,42 @@ export class ProviderElementContext {
|
||||
private _seenProviders = new CompileTokenMap<boolean>();
|
||||
private _allProviders: CompileTokenMap<ProviderAst>;
|
||||
private _attrs: {[key: string]: string};
|
||||
private _hasViewContainer: boolean = false;
|
||||
|
||||
constructor(private _viewContext: ProviderViewContext, private _parent: ProviderElementContext,
|
||||
private _isViewRoot: boolean, private _directiveAsts: DirectiveAst[],
|
||||
attrs: AttrAst[], private _sourceSpan: ParseSourceSpan) {
|
||||
attrs: AttrAst[], vars: VariableAst[], private _sourceSpan: ParseSourceSpan) {
|
||||
this._attrs = {};
|
||||
attrs.forEach((attrAst) => this._attrs[attrAst.name] = attrAst.value);
|
||||
var directivesMeta = _directiveAsts.map(directiveAst => directiveAst.directive);
|
||||
this._allProviders =
|
||||
_resolveProvidersFromDirectives(directivesMeta, _sourceSpan, _viewContext.errors);
|
||||
this._contentQueries = _getContentQueries(directivesMeta);
|
||||
var queriedTokens = new CompileTokenMap<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
|
||||
this._allProviders.values().forEach((provider) => {
|
||||
if (provider.eager || this.isQueried(provider.token)) {
|
||||
this._getLocalProvider(provider.providerType, provider.token, true);
|
||||
var eager = provider.eager || isPresent(queriedTokens.get(provider.token));
|
||||
if (eager) {
|
||||
this._getOrCreateLocalProvider(provider.providerType, provider.token, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
afterElement() {
|
||||
// collect lazy providers
|
||||
this._allProviders.values().forEach(
|
||||
(provider) => { this._getLocalProvider(provider.providerType, provider.token, false); });
|
||||
this._allProviders.values().forEach((provider) => {
|
||||
this._getOrCreateLocalProvider(provider.providerType, provider.token, false);
|
||||
});
|
||||
}
|
||||
|
||||
get transformProviders(): ProviderAst[] { return this._transformedProviders.values(); }
|
||||
@ -101,30 +115,42 @@ export class ProviderElementContext {
|
||||
return sortedDirectives;
|
||||
}
|
||||
|
||||
private isQueried(token: CompileTokenMetadata): boolean {
|
||||
get transformedHasViewContainer(): boolean { return this._hasViewContainer; }
|
||||
|
||||
private _addQueryReadsTo(token: CompileTokenMetadata, queryReadTokens: CompileTokenMap<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 distance = 0;
|
||||
var queries: CompileQueryMetadata[];
|
||||
while (currentEl !== null) {
|
||||
var localQueries = currentEl._contentQueries.get(token);
|
||||
if (isPresent(localQueries)) {
|
||||
if (localQueries.some((query) => query.descendants || distance <= 1)) {
|
||||
return true;
|
||||
}
|
||||
queries = currentEl._contentQueries.get(token);
|
||||
if (isPresent(queries)) {
|
||||
ListWrapper.addAll(result, queries.filter((query) => query.descendants || distance <= 1));
|
||||
}
|
||||
if (currentEl._directiveAsts.length > 0) {
|
||||
distance++;
|
||||
}
|
||||
currentEl = currentEl._parent;
|
||||
}
|
||||
if (isPresent(this._viewContext.viewQueries.get(token))) {
|
||||
return true;
|
||||
queries = this._viewContext.viewQueries.get(token);
|
||||
if (isPresent(queries)) {
|
||||
ListWrapper.addAll(result, queries);
|
||||
}
|
||||
return false;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private _getLocalProvider(requestingProviderType: ProviderAstType, token: CompileTokenMetadata,
|
||||
eager: boolean): ProviderAst {
|
||||
private _getOrCreateLocalProvider(requestingProviderType: ProviderAstType,
|
||||
token: CompileTokenMetadata, eager: boolean): ProviderAst {
|
||||
var resolvedProvider = this._allProviders.get(token);
|
||||
if (isBlank(resolvedProvider) ||
|
||||
((requestingProviderType === ProviderAstType.Directive ||
|
||||
@ -198,17 +224,19 @@ export class ProviderElementContext {
|
||||
if (dep.token.equalsTo(identifierToken(Identifiers.Renderer)) ||
|
||||
dep.token.equalsTo(identifierToken(Identifiers.ElementRef)) ||
|
||||
dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef)) ||
|
||||
dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef)) ||
|
||||
dep.token.equalsTo(identifierToken(Identifiers.TemplateRef))) {
|
||||
return dep;
|
||||
}
|
||||
if (dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef))) {
|
||||
this._hasViewContainer = true;
|
||||
}
|
||||
}
|
||||
// access the injector
|
||||
if (dep.token.equalsTo(identifierToken(Identifiers.Injector))) {
|
||||
return dep;
|
||||
}
|
||||
// access providers
|
||||
if (isPresent(this._getLocalProvider(requestingProviderType, dep.token, eager))) {
|
||||
if (isPresent(this._getOrCreateLocalProvider(requestingProviderType, dep.token, eager))) {
|
||||
return dep;
|
||||
}
|
||||
}
|
||||
@ -393,11 +421,11 @@ function _getContentQueries(
|
||||
|
||||
function _addQueryToTokenMap(map: CompileTokenMap<CompileQueryMetadata[]>,
|
||||
query: CompileQueryMetadata) {
|
||||
query.selectors.forEach((selector) => {
|
||||
var entry = map.get(selector);
|
||||
query.selectors.forEach((token: CompileTokenMetadata) => {
|
||||
var entry = map.get(token);
|
||||
if (isBlank(entry)) {
|
||||
entry = [];
|
||||
map.add(selector, entry);
|
||||
map.add(token, entry);
|
||||
}
|
||||
entry.push(query);
|
||||
});
|
||||
|
@ -225,8 +225,8 @@ class CompiledTemplate {
|
||||
viewFactory: Function = null;
|
||||
proxyViewFactory: Function;
|
||||
constructor() {
|
||||
this.proxyViewFactory = (viewManager, childInjector, contextEl) =>
|
||||
this.viewFactory(viewManager, childInjector, contextEl);
|
||||
this.proxyViewFactory = (viewUtils, childInjector, contextEl) =>
|
||||
this.viewFactory(viewUtils, childInjector, contextEl);
|
||||
}
|
||||
|
||||
init(viewFactory: Function) { this.viewFactory = viewFactory; }
|
||||
|
@ -295,7 +295,8 @@ export class RuntimeMetadataResolver {
|
||||
selectors: selectors,
|
||||
first: q.first,
|
||||
descendants: q.descendants,
|
||||
propertyName: propertyName
|
||||
propertyName: propertyName,
|
||||
read: isPresent(q.read) ? this.getTokenMetadata(q.read) : null
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -98,8 +98,9 @@ export class ElementAst implements TemplateAst {
|
||||
constructor(public name: string, public attrs: AttrAst[],
|
||||
public inputs: BoundElementPropertyAst[], public outputs: BoundEventAst[],
|
||||
public exportAsVars: VariableAst[], public directives: DirectiveAst[],
|
||||
public providers: ProviderAst[], public children: TemplateAst[],
|
||||
public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
|
||||
public providers: ProviderAst[], public hasViewContainer: boolean,
|
||||
public children: TemplateAst[], public ngContentIndex: number,
|
||||
public sourceSpan: ParseSourceSpan) {}
|
||||
|
||||
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||
return visitor.visitElement(this, context);
|
||||
@ -129,8 +130,8 @@ export class ElementAst implements TemplateAst {
|
||||
export class EmbeddedTemplateAst implements TemplateAst {
|
||||
constructor(public attrs: AttrAst[], public outputs: BoundEventAst[], public vars: VariableAst[],
|
||||
public directives: DirectiveAst[], public providers: ProviderAst[],
|
||||
public children: TemplateAst[], public ngContentIndex: number,
|
||||
public sourceSpan: ParseSourceSpan) {}
|
||||
public hasViewContainer: boolean, public children: TemplateAst[],
|
||||
public ngContentIndex: number, public sourceSpan: ParseSourceSpan) {}
|
||||
|
||||
visit(visitor: TemplateAstVisitor, context: any): any {
|
||||
return visitor.visitEmbeddedTemplate(this, context);
|
||||
|
@ -328,7 +328,7 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
var isViewRoot = parent.isTemplateElement || hasInlineTemplates;
|
||||
var providerContext =
|
||||
new ProviderElementContext(this.providerViewContext, parent.providerContext, isViewRoot,
|
||||
directiveAsts, attrs, element.sourceSpan);
|
||||
directiveAsts, attrs, vars, element.sourceSpan);
|
||||
var children = htmlVisitAll(
|
||||
preparsedElement.nonBindable ? NON_BINDABLE_VISITOR : this, element.children,
|
||||
ElementContext.create(isTemplateElement, directiveAsts,
|
||||
@ -355,10 +355,10 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
this._assertNoComponentsNorElementBindingsOnTemplate(directiveAsts, elementProps,
|
||||
element.sourceSpan);
|
||||
|
||||
parsedElement =
|
||||
new EmbeddedTemplateAst(attrs, events, vars, providerContext.transformedDirectiveAsts,
|
||||
providerContext.transformProviders, children,
|
||||
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
||||
parsedElement = new EmbeddedTemplateAst(
|
||||
attrs, events, vars, providerContext.transformedDirectiveAsts,
|
||||
providerContext.transformProviders, providerContext.transformedHasViewContainer, children,
|
||||
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
||||
} else {
|
||||
this._assertOnlyOneComponent(directiveAsts, element.sourceSpan);
|
||||
var elementExportAsVars = vars.filter(varAst => varAst.value.length === 0);
|
||||
@ -367,7 +367,8 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
|
||||
parsedElement = new ElementAst(
|
||||
nodeName, attrs, elementProps, events, elementExportAsVars,
|
||||
providerContext.transformedDirectiveAsts, providerContext.transformProviders, children,
|
||||
providerContext.transformedDirectiveAsts, providerContext.transformProviders,
|
||||
providerContext.transformedHasViewContainer, children,
|
||||
hasInlineTemplates ? null : ngContentIndex, element.sourceSpan);
|
||||
}
|
||||
if (hasInlineTemplates) {
|
||||
@ -382,12 +383,13 @@ class TemplateParseVisitor implements HtmlAstVisitor {
|
||||
templateDirectiveAsts, templateElementProps, element.sourceSpan);
|
||||
var templateProviderContext = new ProviderElementContext(
|
||||
this.providerViewContext, parent.providerContext, parent.isTemplateElement,
|
||||
templateDirectiveAsts, [], element.sourceSpan);
|
||||
templateDirectiveAsts, [], templateVars, element.sourceSpan);
|
||||
templateProviderContext.afterElement();
|
||||
|
||||
parsedElement = new EmbeddedTemplateAst([], [], templateVars,
|
||||
templateProviderContext.transformedDirectiveAsts,
|
||||
templateProviderContext.transformProviders,
|
||||
templateProviderContext.transformedHasViewContainer,
|
||||
[parsedElement], ngContentIndex, element.sourceSpan);
|
||||
}
|
||||
return parsedElement;
|
||||
@ -765,8 +767,8 @@ class NonBindableVisitor implements HtmlAstVisitor {
|
||||
var selector = createElementCssSelector(ast.name, attrNameAndValues);
|
||||
var ngContentIndex = parent.findNgContentIndex(selector);
|
||||
var children = htmlVisitAll(this, ast.children, EMPTY_ELEMENT_CONTEXT);
|
||||
return new ElementAst(ast.name, htmlVisitAll(this, ast.attrs), [], [], [], [], [], children,
|
||||
ngContentIndex, ast.sourceSpan);
|
||||
return new ElementAst(ast.name, htmlVisitAll(this, ast.attrs), [], [], [], [], [], false,
|
||||
children, ngContentIndex, ast.sourceSpan);
|
||||
}
|
||||
visitComment(ast: HtmlCommentAst, context: any): any { return null; }
|
||||
visitAttr(ast: HtmlAttrAst, context: any): AttrAst {
|
||||
|
@ -30,13 +30,13 @@ export class CompileNode {
|
||||
|
||||
export class CompileElement extends CompileNode {
|
||||
static createNull(): CompileElement {
|
||||
return new CompileElement(null, null, null, null, null, [], [], {});
|
||||
return new CompileElement(null, null, null, null, null, null, [], [], false, false, {});
|
||||
}
|
||||
|
||||
private _compViewExpr: o.Expression = null;
|
||||
public component: CompileDirectiveMetadata = null;
|
||||
private _appElement: o.Expression;
|
||||
private _defaultInjector: o.Expression;
|
||||
public appElement: o.ReadPropExpr;
|
||||
public elementRef: o.Expression;
|
||||
public injector: o.Expression;
|
||||
private _instances = new CompileTokenMap<o.Expression>();
|
||||
private _resolvedProviders: CompileTokenMap<ProviderAst>;
|
||||
|
||||
@ -50,17 +50,45 @@ export class CompileElement extends CompileNode {
|
||||
|
||||
constructor(parent: CompileElement, view: CompileView, nodeIndex: number,
|
||||
renderNode: o.Expression, sourceAst: TemplateAst,
|
||||
public component: CompileDirectiveMetadata,
|
||||
private _directives: CompileDirectiveMetadata[],
|
||||
private _resolvedProvidersArray: ProviderAst[],
|
||||
private _resolvedProvidersArray: ProviderAst[], public hasViewContainer: boolean,
|
||||
public hasEmbeddedView: boolean,
|
||||
public variableTokens: {[key: string]: CompileTokenMetadata}) {
|
||||
super(parent, view, nodeIndex, renderNode, sourceAst);
|
||||
this.elementRef = o.importExpr(Identifiers.ElementRef).instantiate([this.renderNode]);
|
||||
this._instances.add(identifierToken(Identifiers.ElementRef), this.elementRef);
|
||||
this.injector = o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]);
|
||||
this._instances.add(identifierToken(Identifiers.Injector), this.injector);
|
||||
this._instances.add(identifierToken(Identifiers.Renderer), o.THIS_EXPR.prop('renderer'));
|
||||
if (this.hasViewContainer || this.hasEmbeddedView || isPresent(this.component)) {
|
||||
this._createAppElement();
|
||||
}
|
||||
}
|
||||
|
||||
setComponent(component: CompileDirectiveMetadata, compViewExpr: o.Expression) {
|
||||
this.component = component;
|
||||
private _createAppElement() {
|
||||
var fieldName = `_appEl_${this.nodeIndex}`;
|
||||
var parentNodeIndex = this.isRootElement() ? null : this.parent.nodeIndex;
|
||||
this.view.fields.push(new o.ClassField(fieldName, o.importType(Identifiers.AppElement),
|
||||
[o.StmtModifier.Private]));
|
||||
var statement = o.THIS_EXPR.prop(fieldName)
|
||||
.set(o.importExpr(Identifiers.AppElement)
|
||||
.instantiate([
|
||||
o.literal(this.nodeIndex),
|
||||
o.literal(parentNodeIndex),
|
||||
o.THIS_EXPR,
|
||||
this.renderNode
|
||||
]))
|
||||
.toStmt();
|
||||
this.view.createMethod.addStmt(statement);
|
||||
this.appElement = o.THIS_EXPR.prop(fieldName);
|
||||
this._instances.add(identifierToken(Identifiers.AppElement), this.appElement);
|
||||
}
|
||||
|
||||
setComponentView(compViewExpr: o.Expression) {
|
||||
this._compViewExpr = compViewExpr;
|
||||
this.contentNodesByNgContentIndex =
|
||||
ListWrapper.createFixedSize(component.template.ngContentSelectors.length);
|
||||
ListWrapper.createFixedSize(this.component.template.ngContentSelectors.length);
|
||||
for (var i = 0; i < this.contentNodesByNgContentIndex.length; i++) {
|
||||
this.contentNodesByNgContentIndex[i] = [];
|
||||
}
|
||||
@ -71,7 +99,7 @@ export class CompileElement extends CompileNode {
|
||||
if (isPresent(embeddedView)) {
|
||||
var createTemplateRefExpr =
|
||||
o.importExpr(Identifiers.TemplateRef_)
|
||||
.instantiate([this.getOrCreateAppElement(), this.embeddedView.viewFactory]);
|
||||
.instantiate([this.appElement, this.embeddedView.viewFactory]);
|
||||
var provider = new CompileProviderMetadata(
|
||||
{token: identifierToken(Identifiers.TemplateRef), useValue: createTemplateRefExpr});
|
||||
// Add TemplateRef as first provider as it does not have deps on other providers
|
||||
@ -82,6 +110,11 @@ export class CompileElement extends CompileNode {
|
||||
}
|
||||
|
||||
beforeChildren(): void {
|
||||
if (this.hasViewContainer) {
|
||||
this._instances.add(identifierToken(Identifiers.ViewContainerRef),
|
||||
this.appElement.prop('vcRef'));
|
||||
}
|
||||
|
||||
this._resolvedProviders = new CompileTokenMap<ProviderAst>();
|
||||
this._resolvedProvidersArray.forEach(provider =>
|
||||
this._resolvedProviders.add(provider.token, provider));
|
||||
@ -127,36 +160,54 @@ export class CompileElement extends CompileNode {
|
||||
var directive = this._directives[i];
|
||||
directive.queries.forEach((queryMeta) => { this._addQuery(queryMeta, directiveInstance); });
|
||||
}
|
||||
var queriesWithReads: _QueryWithRead[] = [];
|
||||
this._resolvedProviders.values().forEach((resolvedProvider) => {
|
||||
var queriesForProvider = this._getQueriesFor(resolvedProvider.token);
|
||||
var providerExpr = this._instances.get(resolvedProvider.token);
|
||||
queriesForProvider.forEach((query) => { query.addValue(providerExpr, this.view); });
|
||||
ListWrapper.addAll(
|
||||
queriesWithReads,
|
||||
queriesForProvider.map(query => new _QueryWithRead(query, resolvedProvider.token)));
|
||||
});
|
||||
StringMapWrapper.forEach(this.variableTokens, (_, varName) => {
|
||||
var token = this.variableTokens[varName];
|
||||
var varValue;
|
||||
var varValueForQuery;
|
||||
if (isPresent(token)) {
|
||||
varValue = varValueForQuery = this._instances.get(token);
|
||||
varValue = this._instances.get(token);
|
||||
} else {
|
||||
varValueForQuery = this.getOrCreateAppElement().prop('ref');
|
||||
varValue = this.renderNode;
|
||||
}
|
||||
this.view.variables.set(varName, varValue);
|
||||
this.view.namedAppElements.push([varName, this.getOrCreateAppElement()]);
|
||||
|
||||
var queriesForProvider = this._getQueriesFor(new CompileTokenMetadata({value: varName}));
|
||||
queriesForProvider.forEach((query) => { query.addValue(varValueForQuery, this.view); });
|
||||
var varToken = new CompileTokenMetadata({value: varName});
|
||||
ListWrapper.addAll(queriesWithReads, this._getQueriesFor(varToken)
|
||||
.map(query => new _QueryWithRead(query, varToken)));
|
||||
});
|
||||
queriesWithReads.forEach((queryWithRead) => {
|
||||
var value: o.Expression;
|
||||
if (isPresent(queryWithRead.read.identifier)) {
|
||||
// query for an identifier
|
||||
value = this._instances.get(queryWithRead.read);
|
||||
} else {
|
||||
// query for a variable
|
||||
var token = this.variableTokens[queryWithRead.read.value];
|
||||
if (isPresent(token)) {
|
||||
value = this._instances.get(token);
|
||||
} else {
|
||||
value = this.elementRef;
|
||||
}
|
||||
}
|
||||
if (isPresent(value)) {
|
||||
queryWithRead.query.addValue(value, this.view);
|
||||
}
|
||||
});
|
||||
|
||||
if (isPresent(this.component)) {
|
||||
var componentConstructorViewQueryList =
|
||||
isPresent(this.component) ? o.literalArr(this._componentConstructorViewQueryLists) :
|
||||
o.NULL_EXPR;
|
||||
var compExpr = isPresent(this.getComponent()) ? this.getComponent() : o.NULL_EXPR;
|
||||
this.view.createMethod.addStmt(
|
||||
this.getOrCreateAppElement()
|
||||
.callMethod('initComponent',
|
||||
[compExpr, componentConstructorViewQueryList, this._compViewExpr])
|
||||
this.appElement.callMethod(
|
||||
'initComponent',
|
||||
[compExpr, componentConstructorViewQueryList, this._compViewExpr])
|
||||
.toStmt());
|
||||
}
|
||||
}
|
||||
@ -202,43 +253,6 @@ export class CompileElement extends CompileNode {
|
||||
return res;
|
||||
}
|
||||
|
||||
getOptionalAppElement(): o.Expression { return this._appElement; }
|
||||
|
||||
getOrCreateAppElement(): o.Expression {
|
||||
if (isBlank(this._appElement)) {
|
||||
var parentNodeIndex = this.isRootElement() ? null : this.parent.nodeIndex;
|
||||
var fieldName = `_appEl_${this.nodeIndex}`;
|
||||
this.view.fields.push(new o.ClassField(fieldName, o.importType(Identifiers.AppElement),
|
||||
[o.StmtModifier.Private]));
|
||||
var statement = o.THIS_EXPR.prop(fieldName)
|
||||
.set(o.importExpr(Identifiers.AppElement)
|
||||
.instantiate([
|
||||
o.literal(this.nodeIndex),
|
||||
o.literal(parentNodeIndex),
|
||||
o.THIS_EXPR,
|
||||
this.renderNode
|
||||
]))
|
||||
.toStmt();
|
||||
this.view.createMethod.addStmt(statement);
|
||||
this._appElement = o.THIS_EXPR.prop(fieldName);
|
||||
}
|
||||
return this._appElement;
|
||||
}
|
||||
|
||||
getOrCreateInjector(): o.Expression {
|
||||
if (isBlank(this._defaultInjector)) {
|
||||
var fieldName = `_inj_${this.nodeIndex}`;
|
||||
this.view.fields.push(new o.ClassField(fieldName, o.importType(Identifiers.Injector),
|
||||
[o.StmtModifier.Private]));
|
||||
var statement = o.THIS_EXPR.prop(fieldName)
|
||||
.set(o.THIS_EXPR.callMethod('injector', [o.literal(this.nodeIndex)]))
|
||||
.toStmt();
|
||||
this.view.createMethod.addStmt(statement);
|
||||
this._defaultInjector = o.THIS_EXPR.prop(fieldName);
|
||||
}
|
||||
return this._defaultInjector;
|
||||
}
|
||||
|
||||
private _getQueriesFor(token: CompileTokenMetadata): CompileQuery[] {
|
||||
var result: CompileQuery[] = [];
|
||||
var currentEl: CompileElement = this;
|
||||
@ -289,30 +303,20 @@ export class CompileElement extends CompileNode {
|
||||
}
|
||||
|
||||
if (isPresent(dep.token)) {
|
||||
// access builtins
|
||||
// access builtins with special visibility
|
||||
if (isBlank(result)) {
|
||||
if (dep.token.equalsTo(identifierToken(Identifiers.Renderer))) {
|
||||
result = o.THIS_EXPR.prop('renderer');
|
||||
} else if (dep.token.equalsTo(identifierToken(Identifiers.ElementRef))) {
|
||||
result = this.getOrCreateAppElement().prop('ref');
|
||||
} else if (dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef))) {
|
||||
if (dep.token.equalsTo(identifierToken(Identifiers.ChangeDetectorRef))) {
|
||||
if (requestingProviderType === ProviderAstType.Component) {
|
||||
return this._compViewExpr.prop('ref');
|
||||
} else {
|
||||
return o.THIS_EXPR.prop('ref');
|
||||
}
|
||||
} else if (dep.token.equalsTo(identifierToken(Identifiers.ViewContainerRef))) {
|
||||
result = this.getOrCreateAppElement().prop('vcRef');
|
||||
}
|
||||
}
|
||||
// access providers
|
||||
// access regular providers on the element
|
||||
if (isBlank(result)) {
|
||||
result = this._instances.get(dep.token);
|
||||
}
|
||||
// access the injector
|
||||
if (isBlank(result) && dep.token.equalsTo(identifierToken(Identifiers.Injector))) {
|
||||
result = this.getOrCreateInjector();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -400,3 +404,10 @@ function createProviderProperty(propName: string, provider: ProviderAst,
|
||||
}
|
||||
return o.THIS_EXPR.prop(propName);
|
||||
}
|
||||
|
||||
class _QueryWithRead {
|
||||
public read: CompileTokenMetadata;
|
||||
constructor(public query: CompileQuery, match: CompileTokenMetadata) {
|
||||
this.read = isPresent(query.meta.read) ? query.meta.read : match;
|
||||
}
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ export class CompileQuery {
|
||||
function createQueryValues(viewValues: ViewQueryValues): o.Expression[] {
|
||||
return ListWrapper.flatten(viewValues.values.map((entry) => {
|
||||
if (entry instanceof ViewQueryValues) {
|
||||
return mapNestedViews(entry.view.declarationElement.getOrCreateAppElement(), entry.view,
|
||||
return mapNestedViews(entry.view.declarationElement.appElement, entry.view,
|
||||
createQueryValues(entry));
|
||||
} else {
|
||||
return <o.Expression>entry;
|
||||
|
@ -33,9 +33,9 @@ export class CompilePipe {
|
||||
export class CompileView implements NameResolver {
|
||||
public viewType: ViewType;
|
||||
public viewQueries: CompileTokenMap<CompileQuery[]>;
|
||||
public namedAppElements: Array<Array<string | o.Expression>> = [];
|
||||
|
||||
public nodes: CompileNode[] = [];
|
||||
// root nodes or AppElements for ViewContainers
|
||||
public rootNodesOrAppElements: o.Expression[] = [];
|
||||
|
||||
public bindings: CompileBinding[] = [];
|
||||
|
@ -59,7 +59,7 @@ export class ChangeDetectionStrategyEnum {
|
||||
}
|
||||
|
||||
export class ViewConstructorVars {
|
||||
static viewManager = o.variable('viewManager');
|
||||
static viewUtils = o.variable('viewUtils');
|
||||
static parentInjector = o.variable('parentInjector');
|
||||
static declarationEl = o.variable('declarationEl');
|
||||
}
|
||||
@ -67,7 +67,7 @@ export class ViewConstructorVars {
|
||||
export class ViewProperties {
|
||||
static renderer = o.THIS_EXPR.prop('renderer');
|
||||
static projectableNodes = o.THIS_EXPR.prop('projectableNodes');
|
||||
static viewManager = o.THIS_EXPR.prop('viewManager');
|
||||
static viewUtils = o.THIS_EXPR.prop('viewUtils');
|
||||
}
|
||||
|
||||
export class EventHandlerVars { static event = o.variable('$event'); }
|
||||
|
@ -67,10 +67,9 @@ export class CompileEventListener {
|
||||
}
|
||||
|
||||
finishMethod() {
|
||||
var markPathToRootStart =
|
||||
this._hasComponentHostListener ?
|
||||
this.compileElement.getOrCreateAppElement().prop('componentView') :
|
||||
o.THIS_EXPR;
|
||||
var markPathToRootStart = this._hasComponentHostListener ?
|
||||
this.compileElement.appElement.prop('componentView') :
|
||||
o.THIS_EXPR;
|
||||
var resultExpr: o.Expression = o.literal(true);
|
||||
this._actionResultExprs.forEach((expr) => { resultExpr = resultExpr.and(expr); });
|
||||
var stmts =
|
||||
|
@ -189,8 +189,7 @@ export function bindDirectiveInputs(directiveAst: DirectiveAst, directiveInstanc
|
||||
});
|
||||
if (isOnPushComp) {
|
||||
detectChangesInInputsMethod.addStmt(new o.IfStmt(DetectChangesVars.changed, [
|
||||
compileElement.getOrCreateAppElement()
|
||||
.prop('componentView')
|
||||
compileElement.appElement.prop('componentView')
|
||||
.callMethod('markAsCheckOnce', [])
|
||||
.toStmt()
|
||||
]));
|
||||
|
@ -92,14 +92,15 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||
|
||||
private _addRootNodeAndProject(node: CompileNode, ngContentIndex: number,
|
||||
parent: CompileElement) {
|
||||
var appEl = node instanceof CompileElement ? node.getOptionalAppElement() : null;
|
||||
var vcAppEl =
|
||||
(node instanceof CompileElement && node.hasViewContainer) ? node.appElement : null;
|
||||
if (this._isRootNode(parent)) {
|
||||
// store root nodes only for embedded/host views
|
||||
// store appElement as root node only for ViewContainers
|
||||
if (this.view.viewType !== ViewType.COMPONENT) {
|
||||
this.view.rootNodesOrAppElements.push(isPresent(appEl) ? appEl : node.renderNode);
|
||||
this.view.rootNodesOrAppElements.push(isPresent(vcAppEl) ? vcAppEl : node.renderNode);
|
||||
}
|
||||
} else if (isPresent(parent.component) && isPresent(ngContentIndex)) {
|
||||
parent.addContentNode(ngContentIndex, isPresent(appEl) ? appEl : node.renderNode);
|
||||
parent.addContentNode(ngContentIndex, isPresent(vcAppEl) ? vcAppEl : node.renderNode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -196,7 +197,7 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||
this.view.fields.push(
|
||||
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderElement),
|
||||
[o.StmtModifier.Private]));
|
||||
var createRenderNode = o.THIS_EXPR.prop(fieldName).set(createRenderNodeExpr).toStmt();
|
||||
this.view.createMethod.addStmt(o.THIS_EXPR.prop(fieldName).set(createRenderNodeExpr).toStmt());
|
||||
|
||||
var renderNode = o.THIS_EXPR.prop(fieldName);
|
||||
|
||||
@ -204,7 +205,6 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||
var directives = ast.directives.map(directiveAst => directiveAst.directive);
|
||||
var variables =
|
||||
_readHtmlAndDirectiveVariables(ast.exportAsVars, ast.directives, this.view.viewType);
|
||||
this.view.createMethod.addStmt(createRenderNode);
|
||||
var htmlAttrs = _readHtmlAttrs(ast.attrs);
|
||||
var attrNameAndValues = _mergeHtmlAndDirectiveAttrs(htmlAttrs, directives);
|
||||
for (var i = 0; i < attrNameAndValues.length; i++) {
|
||||
@ -216,8 +216,9 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||
[renderNode, o.literal(attrName), o.literal(attrValue)])
|
||||
.toStmt());
|
||||
}
|
||||
var compileElement = new CompileElement(parent, this.view, nodeIndex, renderNode, ast,
|
||||
directives, ast.providers, variables);
|
||||
var compileElement =
|
||||
new CompileElement(parent, this.view, nodeIndex, renderNode, ast, component, directives,
|
||||
ast.providers, ast.hasViewContainer, false, variables);
|
||||
this.view.nodes.push(compileElement);
|
||||
var compViewExpr: o.ReadVarExpr = null;
|
||||
if (isPresent(component)) {
|
||||
@ -225,14 +226,14 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||
new CompileIdentifierMetadata({name: getViewFactoryName(component, 0)});
|
||||
this.targetDependencies.push(new ViewCompileDependency(component, nestedComponentIdentifier));
|
||||
compViewExpr = o.variable(`compView_${nodeIndex}`);
|
||||
compileElement.setComponentView(compViewExpr);
|
||||
this.view.createMethod.addStmt(compViewExpr.set(o.importExpr(nestedComponentIdentifier)
|
||||
.callFn([
|
||||
ViewProperties.viewManager,
|
||||
compileElement.getOrCreateInjector(),
|
||||
compileElement.getOrCreateAppElement()
|
||||
ViewProperties.viewUtils,
|
||||
compileElement.injector,
|
||||
compileElement.appElement
|
||||
]))
|
||||
.toDeclStmt());
|
||||
compileElement.setComponent(component, compViewExpr);
|
||||
}
|
||||
compileElement.beforeChildren();
|
||||
this._addRootNodeAndProject(compileElement, ast.ngContentIndex, parent);
|
||||
@ -259,24 +260,25 @@ class ViewBuilderVisitor implements TemplateAstVisitor {
|
||||
this.view.fields.push(
|
||||
new o.ClassField(fieldName, o.importType(this.view.genConfig.renderTypes.renderComment),
|
||||
[o.StmtModifier.Private]));
|
||||
var createRenderNode = o.THIS_EXPR.prop(fieldName)
|
||||
.set(ViewProperties.renderer.callMethod(
|
||||
'createTemplateAnchor',
|
||||
[
|
||||
this._getParentRenderNode(parent),
|
||||
this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast)
|
||||
]))
|
||||
.toStmt();
|
||||
this.view.createMethod.addStmt(
|
||||
o.THIS_EXPR.prop(fieldName)
|
||||
.set(ViewProperties.renderer.callMethod(
|
||||
'createTemplateAnchor',
|
||||
[
|
||||
this._getParentRenderNode(parent),
|
||||
this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast)
|
||||
]))
|
||||
.toStmt());
|
||||
var renderNode = o.THIS_EXPR.prop(fieldName);
|
||||
|
||||
var templateVariableBindings = ast.vars.map(
|
||||
varAst => [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]);
|
||||
|
||||
var directives = ast.directives.map(directiveAst => directiveAst.directive);
|
||||
var compileElement = new CompileElement(parent, this.view, nodeIndex, renderNode, ast,
|
||||
directives, ast.providers, {});
|
||||
var compileElement =
|
||||
new CompileElement(parent, this.view, nodeIndex, renderNode, ast, null, directives,
|
||||
ast.providers, ast.hasViewContainer, true, {});
|
||||
this.view.nodes.push(compileElement);
|
||||
this.view.createMethod.addStmt(createRenderNode);
|
||||
|
||||
this.nestedViewCount++;
|
||||
var embeddedView = new CompileView(
|
||||
@ -413,7 +415,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
|
||||
var emptyTemplateVariableBindings =
|
||||
view.templateVariableBindings.map((entry) => [entry[0], o.NULL_EXPR]);
|
||||
var viewConstructorArgs = [
|
||||
new o.FnParam(ViewConstructorVars.viewManager.name, o.importType(Identifiers.AppViewManager_)),
|
||||
new o.FnParam(ViewConstructorVars.viewUtils.name, o.importType(Identifiers.ViewUtils)),
|
||||
new o.FnParam(ViewConstructorVars.parentInjector.name, o.importType(Identifiers.Injector)),
|
||||
new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement))
|
||||
];
|
||||
@ -423,7 +425,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
|
||||
renderCompTypeVar,
|
||||
ViewTypeEnum.fromValue(view.viewType),
|
||||
o.literalMap(emptyTemplateVariableBindings),
|
||||
ViewConstructorVars.viewManager,
|
||||
ViewConstructorVars.viewUtils,
|
||||
ViewConstructorVars.parentInjector,
|
||||
ViewConstructorVars.declarationEl,
|
||||
ChangeDetectionStrategyEnum.fromValue(getChangeDetectionMode(view)),
|
||||
@ -462,7 +464,7 @@ function createViewClass(view: CompileView, renderCompTypeVar: o.ReadVarExpr,
|
||||
function createViewFactory(view: CompileView, viewClass: o.ClassStmt,
|
||||
renderCompTypeVar: o.ReadVarExpr): o.Statement {
|
||||
var viewFactoryArgs = [
|
||||
new o.FnParam(ViewConstructorVars.viewManager.name, o.importType(Identifiers.AppViewManager_)),
|
||||
new o.FnParam(ViewConstructorVars.viewUtils.name, o.importType(Identifiers.ViewUtils)),
|
||||
new o.FnParam(ViewConstructorVars.parentInjector.name, o.importType(Identifiers.Injector)),
|
||||
new o.FnParam(ViewConstructorVars.declarationEl.name, o.importType(Identifiers.AppElement))
|
||||
];
|
||||
@ -478,15 +480,16 @@ function createViewFactory(view: CompileView, viewClass: o.ClassStmt,
|
||||
initRenderCompTypeStmts = [
|
||||
new o.IfStmt(renderCompTypeVar.identical(o.NULL_EXPR),
|
||||
[
|
||||
renderCompTypeVar.set(ViewConstructorVars.viewManager
|
||||
.callMethod('createRenderComponentType',
|
||||
[
|
||||
o.literal(templateUrlInfo),
|
||||
o.literal(
|
||||
view.component.template.ngContentSelectors.length),
|
||||
ViewEncapsulationEnum.fromValue(view.component.template.encapsulation),
|
||||
view.styles
|
||||
]))
|
||||
renderCompTypeVar.set(ViewConstructorVars
|
||||
.viewUtils.callMethod('createRenderComponentType',
|
||||
[
|
||||
o.literal(templateUrlInfo),
|
||||
o.literal(view.component
|
||||
.template.ngContentSelectors.length),
|
||||
ViewEncapsulationEnum
|
||||
.fromValue(view.component.template.encapsulation),
|
||||
view.styles
|
||||
]))
|
||||
.toStmt()
|
||||
])
|
||||
];
|
||||
@ -513,7 +516,7 @@ function generateCreateMethod(view: CompileView): o.Statement[] {
|
||||
}
|
||||
var resultExpr: o.Expression;
|
||||
if (view.viewType === ViewType.HOST) {
|
||||
resultExpr = (<CompileElement>view.nodes[0]).getOrCreateAppElement();
|
||||
resultExpr = (<CompileElement>view.nodes[0]).appElement;
|
||||
} else {
|
||||
resultExpr = o.NULL_EXPR;
|
||||
}
|
||||
@ -523,7 +526,6 @@ function generateCreateMethod(view: CompileView): o.Statement[] {
|
||||
[
|
||||
createFlatArray(view.rootNodesOrAppElements),
|
||||
o.literalArr(view.nodes.map(node => node.renderNode)),
|
||||
o.literalMap(view.namedAppElements),
|
||||
o.literalArr(view.disposables),
|
||||
o.literalArr(view.subscriptions)
|
||||
])
|
||||
|
Reference in New Issue
Block a user