feat(core): speed up view creation via code gen for view factories.

BREAKING CHANGE:
- Platform pipes can only contain types and arrays of types,
  but no bindings any more.
- When using transformers, platform pipes need to be specified explicitly
  in the pubspec.yaml via the new config option
  `platform_pipes`.
- `Compiler.compileInHost` now returns a `HostViewFactoryRef`
- Component view is not yet created when component constructor is called.
  -> use `onInit` lifecycle callback to access the view of a component
- `ViewRef#setLocal` has been moved to new type `EmbeddedViewRef`
- `internalView` is gone, use `EmbeddedViewRef.rootNodes` to access
  the root nodes of an embedded view
- `renderer.setElementProperty`, `..setElementStyle`, `..setElementAttribute` now
  take a native element instead of an ElementRef
- `Renderer` interface now operates on plain native nodes,
  instead of `RenderElementRef`s or `RenderViewRef`s

Closes #5993
This commit is contained in:
Tobias Bosch
2016-01-05 08:56:46 -08:00
parent a08f50badd
commit 7ae23adaff
191 changed files with 6473 additions and 10229 deletions
@@ -169,10 +169,10 @@ export class NgClass implements DoCheck, OnDestroy {
if (className.indexOf(' ') > -1) {
var classes = className.split(/\s+/g);
for (var i = 0, len = classes.length; i < len; i++) {
this._renderer.setElementClass(this._ngEl, classes[i], enabled);
this._renderer.setElementClass(this._ngEl.nativeElement, classes[i], enabled);
}
} else {
this._renderer.setElementClass(this._ngEl, className, enabled);
this._renderer.setElementClass(this._ngEl.nativeElement, className, enabled);
}
}
}
@@ -6,7 +6,7 @@ import {
IterableDiffers,
ViewContainerRef,
TemplateRef,
ViewRef
EmbeddedViewRef
} from 'angular2/core';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
@@ -110,7 +110,8 @@ export class NgFor implements DoCheck {
}
for (var i = 0, ilen = this._viewContainer.length; i < ilen; i++) {
this._viewContainer.get(i).setLocal('last', i === ilen - 1);
var viewRef = <EmbeddedViewRef>this._viewContainer.get(i);
viewRef.setLocal('last', i === ilen - 1);
}
}
@@ -153,7 +154,7 @@ export class NgFor implements DoCheck {
}
class RecordViewTuple {
view: ViewRef;
view: EmbeddedViewRef;
record: any;
constructor(record, view) {
this.record = record;
@@ -92,6 +92,6 @@ export class NgStyle implements DoCheck {
}
private _setStyle(name: string, val: string): void {
this._renderer.setElementStyle(this._ngEl, name, val);
this._renderer.setElementStyle(this._ngEl.nativeElement, name, val);
}
}
@@ -27,7 +27,7 @@ export class CheckboxControlValueAccessor implements ControlValueAccessor {
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: any): void {
this._renderer.setElementProperty(this._elementRef, 'checked', value);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'checked', value);
}
registerOnChange(fn: (_: any) => {}): void { this.onChange = fn; }
registerOnTouched(fn: () => {}): void { this.onTouched = fn; }
@@ -31,7 +31,7 @@ export class DefaultValueAccessor implements ControlValueAccessor {
writeValue(value: any): void {
var normalizedValue = isBlank(value) ? '' : value;
this._renderer.setElementProperty(this._elementRef, 'value', normalizedValue);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', normalizedValue);
}
registerOnChange(fn: (_: any) => void): void { this.onChange = fn; }
@@ -31,7 +31,7 @@ export class NumberValueAccessor implements ControlValueAccessor {
constructor(private _renderer: Renderer, private _elementRef: ElementRef) {}
writeValue(value: number): void {
this._renderer.setElementProperty(this._elementRef, 'value', value);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', value);
}
registerOnChange(fn: (_: number) => void): void {
@@ -51,7 +51,7 @@ export class SelectControlValueAccessor implements ControlValueAccessor {
writeValue(value: any): void {
this.value = value;
this._renderer.setElementProperty(this._elementRef, 'value', value);
this._renderer.setElementProperty(this._elementRef.nativeElement, 'value', value);
}
registerOnChange(fn: () => any): void { this.onChange = fn; }
@@ -80,7 +80,6 @@ export function selectValueAccessor(dir: NgControl,
var defaultAccessor;
var builtinAccessor;
var customAccessor;
valueAccessors.forEach(v => {
if (v instanceof DefaultValueAccessor) {
defaultAccessor = v;
@@ -1,4 +1,4 @@
import {ListWrapper} from 'angular2/src/facade/collection';
import {ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {reflector} from 'angular2/src/core/reflection/reflection';
@@ -43,7 +43,7 @@ export function createChangeDetectorDefinitions(
class ProtoViewVisitor implements TemplateAstVisitor {
viewIndex: number;
boundTextCount: number = 0;
nodeCount: number = 0;
boundElementCount: number = 0;
variableNames: string[] = [];
bindingRecords: BindingRecord[] = [];
@@ -57,6 +57,7 @@ class ProtoViewVisitor implements TemplateAstVisitor {
}
visitEmbeddedTemplate(ast: EmbeddedTemplateAst, context: any): any {
this.nodeCount++;
this.boundElementCount++;
templateVisitAll(this, ast.outputs);
for (var i = 0; i < ast.directives.length; i++) {
@@ -73,6 +74,7 @@ class ProtoViewVisitor implements TemplateAstVisitor {
}
visitElement(ast: ElementAst, context: any): any {
this.nodeCount++;
if (ast.isBound()) {
this.boundElementCount++;
}
@@ -132,14 +134,20 @@ class ProtoViewVisitor implements TemplateAstVisitor {
}
visitAttr(ast: AttrAst, context: any): any { return null; }
visitBoundText(ast: BoundTextAst, context: any): any {
var boundTextIndex = this.boundTextCount++;
this.bindingRecords.push(BindingRecord.createForTextNode(ast.value, boundTextIndex));
var nodeIndex = this.nodeCount++;
this.bindingRecords.push(BindingRecord.createForTextNode(ast.value, nodeIndex));
return null;
}
visitText(ast: TextAst, context: any): any {
this.nodeCount++;
return null;
}
visitText(ast: TextAst, context: any): any { return null; }
visitDirective(ast: DirectiveAst, directiveIndexAsNumber: number): any {
var directiveIndex = new DirectiveIndex(this.boundElementCount - 1, directiveIndexAsNumber);
var directiveMetadata = ast.directive;
var outputsArray = [];
StringMapWrapper.forEach(ast.directive.outputs, (eventName, dirProperty) => outputsArray.push(
[dirProperty, eventName]));
var directiveRecord = new DirectiveRecord({
directiveIndex: directiveIndex,
callAfterContentInit:
@@ -153,7 +161,9 @@ class ProtoViewVisitor implements TemplateAstVisitor {
callOnChanges: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnChanges) !== -1,
callDoCheck: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.DoCheck) !== -1,
callOnInit: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnInit) !== -1,
changeDetection: directiveMetadata.changeDetection
callOnDestroy: directiveMetadata.lifecycleHooks.indexOf(LifecycleHooks.OnDestroy) !== -1,
changeDetection: directiveMetadata.changeDetection,
outputs: outputsArray
});
this.directiveRecords.push(directiveRecord);
@@ -3,6 +3,9 @@ import {SourceExpressions, moduleRef} from './source_module';
import {
ChangeDetectorJITGenerator
} from 'angular2/src/core/change_detection/change_detection_jit_generator';
import {AbstractChangeDetector} from 'angular2/src/core/change_detection/abstract_change_detector';
import {ChangeDetectionUtil} from 'angular2/src/core/change_detection/change_detection_util';
import {ChangeDetectorState} from 'angular2/src/core/change_detection/constants';
import {createChangeDetectorDefinitions} from './change_definition_factory';
import {IS_DART, isJsObject, CONST_EXPR} from 'angular2/src/facade/lang';
@@ -23,6 +26,12 @@ const ABSTRACT_CHANGE_DETECTOR = "AbstractChangeDetector";
const UTIL = "ChangeDetectionUtil";
const CHANGE_DETECTOR_STATE = "ChangeDetectorState";
export const CHANGE_DETECTION_JIT_IMPORTS = CONST_EXPR({
'AbstractChangeDetector': AbstractChangeDetector,
'ChangeDetectionUtil': ChangeDetectionUtil,
'ChangeDetectorState': ChangeDetectorState
});
var ABSTRACT_CHANGE_DETECTOR_MODULE = moduleRef(
`package:angular2/src/core/change_detection/abstract_change_detector${MODULE_SUFFIX}`);
var UTIL_MODULE =
@@ -45,14 +54,8 @@ export class ChangeDetectionCompiler {
}
private _createChangeDetectorFactory(definition: ChangeDetectorDefinition): Function {
if (IS_DART || !this._genConfig.useJit) {
var proto = new DynamicProtoChangeDetector(definition);
return (dispatcher) => proto.instantiate(dispatcher);
} else {
return new ChangeDetectorJITGenerator(definition, UTIL, ABSTRACT_CHANGE_DETECTOR,
CHANGE_DETECTOR_STATE)
.generate();
}
var proto = new DynamicProtoChangeDetector(definition);
return () => proto.instantiate();
}
compileComponentCodeGen(componentType: CompileTypeMetadata, strategy: ChangeDetectionStrategy,
@@ -81,7 +84,7 @@ export class ChangeDetectionCompiler {
definition, `${UTIL_MODULE}${UTIL}`,
`${ABSTRACT_CHANGE_DETECTOR_MODULE}${ABSTRACT_CHANGE_DETECTOR}`,
`${CONSTANTS_MODULE}${CHANGE_DETECTOR_STATE}`);
factories.push(`function(dispatcher) { return new ${codegen.typeName}(dispatcher); }`);
factories.push(`function() { return new ${codegen.typeName}(); }`);
sourcePart = codegen.generateSource();
}
index++;
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -17,7 +17,8 @@ import {TemplateNormalizer} from 'angular2/src/compiler/template_normalizer';
import {RuntimeMetadataResolver} from 'angular2/src/compiler/runtime_metadata';
import {ChangeDetectionCompiler} from 'angular2/src/compiler/change_detector_compiler';
import {StyleCompiler} from 'angular2/src/compiler/style_compiler';
import {CommandCompiler} from 'angular2/src/compiler/command_compiler';
import {ViewCompiler} from 'angular2/src/compiler/view_compiler';
import {ProtoViewCompiler} from 'angular2/src/compiler/proto_view_compiler';
import {TemplateCompiler} from 'angular2/src/compiler/template_compiler';
import {ChangeDetectorGenConfig} from 'angular2/src/core/change_detection/change_detection';
import {Compiler} from 'angular2/src/core/linker/compiler';
@@ -44,7 +45,8 @@ export const COMPILER_PROVIDERS: Array<Type | Provider | any[]> = CONST_EXPR([
RuntimeMetadataResolver,
DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler,
CommandCompiler,
ProtoViewCompiler,
ViewCompiler,
ChangeDetectionCompiler,
new Provider(ChangeDetectorGenConfig, {useFactory: _createChangeDetectorGenConfig, deps: []}),
TemplateCompiler,
@@ -7,6 +7,7 @@ import {
RegExpWrapper,
StringWrapper
} from 'angular2/src/facade/lang';
import {unimplemented} from 'angular2/src/facade/exceptions';
import {StringMapWrapper} from 'angular2/src/facade/collection';
import {
ChangeDetectionStrategy,
@@ -21,6 +22,16 @@ import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/linker/i
// group 2: "event" from "(event)"
var HOST_REG_EXP = /^(?:(?:\[([^\]]+)\])|(?:\(([^\)]+)\)))$/g;
export abstract class CompileMetadataWithType {
static fromJson(data: {[key: string]: any}): CompileMetadataWithType {
return _COMPILE_METADATA_FROM_JSON[data['class']](data);
}
abstract toJson(): {[key: string]: any};
get type(): CompileTypeMetadata { return unimplemented(); }
}
/**
* Metadata regarding compilation of a type.
*/
@@ -107,7 +118,7 @@ export class CompileTemplateMetadata {
/**
* Metadata regarding compilation of a directive.
*/
export class CompileDirectiveMetadata {
export class CompileDirectiveMetadata implements CompileMetadataWithType {
static create({type, isComponent, dynamicLoadable, selector, exportAs, changeDetection, inputs,
outputs, host, lifecycleHooks, template}: {
type?: CompileTypeMetadata,
@@ -241,6 +252,7 @@ export class CompileDirectiveMetadata {
toJson(): {[key: string]: any} {
return {
'class': 'Directive',
'isComponent': this.isComponent,
'dynamicLoadable': this.dynamicLoadable,
'selector': this.selector,
@@ -284,3 +296,38 @@ export function createHostComponentMeta(componentType: CompileTypeMetadata,
selector: '*'
});
}
export class CompilePipeMetadata implements CompileMetadataWithType {
type: CompileTypeMetadata;
name: string;
pure: boolean;
constructor({type, name,
pure}: {type?: CompileTypeMetadata, name?: string, pure?: boolean} = {}) {
this.type = type;
this.name = name;
this.pure = normalizeBool(pure);
}
static fromJson(data: {[key: string]: any}): CompilePipeMetadata {
return new CompilePipeMetadata({
type: isPresent(data['type']) ? CompileTypeMetadata.fromJson(data['type']) : data['type'],
name: data['name'],
pure: data['pure']
});
}
toJson(): {[key: string]: any} {
return {
'class': 'Pipe',
'type': isPresent(this.type) ? this.type.toJson() : null,
'name': this.name,
'pure': this.pure
};
}
}
var _COMPILE_METADATA_FROM_JSON = {
'Directive': CompileDirectiveMetadata.fromJson,
'Pipe': CompilePipeMetadata.fromJson
};
File diff suppressed because it is too large Load Diff
@@ -1,23 +1,23 @@
import {Compiler, Compiler_, internalCreateProtoView} from 'angular2/src/core/linker/compiler';
import {ProtoViewRef} from 'angular2/src/core/linker/view_ref';
import {ProtoViewFactory} from 'angular2/src/core/linker/proto_view_factory';
import {Compiler, Compiler_} from 'angular2/src/core/linker/compiler';
import {HostViewFactoryRef, HostViewFactoryRef_} from 'angular2/src/core/linker/view_ref';
import {TemplateCompiler} from './template_compiler';
import {Injectable} from 'angular2/src/core/di';
import {Type} from 'angular2/src/facade/lang';
import {Promise, PromiseWrapper} from 'angular2/src/facade/async';
export abstract class RuntimeCompiler extends Compiler {}
export abstract class RuntimeCompiler extends Compiler {
abstract compileInHost(componentType: Type): Promise<HostViewFactoryRef>;
abstract clearCache();
}
@Injectable()
export class RuntimeCompiler_ extends Compiler_ implements RuntimeCompiler {
constructor(_protoViewFactory: ProtoViewFactory, private _templateCompiler: TemplateCompiler) {
super(_protoViewFactory);
}
constructor(private _templateCompiler: TemplateCompiler) { super(); }
compileInHost(componentType: Type): Promise<ProtoViewRef> {
compileInHost(componentType: Type): Promise<HostViewFactoryRef_> {
return this._templateCompiler.compileHostComponentRuntime(componentType)
.then(compiledHostTemplate => internalCreateProtoView(this, compiledHostTemplate));
.then(hostViewFactory => new HostViewFactoryRef_(hostViewFactory));
}
clearCache() {
@@ -11,25 +11,29 @@ import {BaseException} from 'angular2/src/facade/exceptions';
import * as cpl from './directive_metadata';
import * as md from 'angular2/src/core/metadata/directives';
import {DirectiveResolver} from 'angular2/src/core/linker/directive_resolver';
import {PipeResolver} from 'angular2/src/core/linker/pipe_resolver';
import {ViewResolver} from 'angular2/src/core/linker/view_resolver';
import {ViewMetadata} from 'angular2/src/core/metadata/view';
import {hasLifecycleHook} from 'angular2/src/core/linker/directive_lifecycle_reflector';
import {LifecycleHooks, LIFECYCLE_HOOKS_VALUES} from 'angular2/src/core/linker/interfaces';
import {reflector} from 'angular2/src/core/reflection/reflection';
import {Injectable, Inject, Optional} from 'angular2/src/core/di';
import {PLATFORM_DIRECTIVES} from 'angular2/src/core/platform_directives_and_pipes';
import {PLATFORM_DIRECTIVES, PLATFORM_PIPES} from 'angular2/src/core/platform_directives_and_pipes';
import {MODULE_SUFFIX} from './util';
import {getUrlScheme} from 'angular2/src/compiler/url_resolver';
@Injectable()
export class RuntimeMetadataResolver {
private _cache = new Map<Type, cpl.CompileDirectiveMetadata>();
private _directiveCache = new Map<Type, cpl.CompileDirectiveMetadata>();
private _pipeCache = new Map<Type, cpl.CompilePipeMetadata>();
constructor(private _directiveResolver: DirectiveResolver, private _viewResolver: ViewResolver,
@Optional() @Inject(PLATFORM_DIRECTIVES) private _platformDirectives: Type[]) {}
constructor(private _directiveResolver: DirectiveResolver, private _pipeResolver: PipeResolver,
private _viewResolver: ViewResolver,
@Optional() @Inject(PLATFORM_DIRECTIVES) private _platformDirectives: Type[],
@Optional() @Inject(PLATFORM_PIPES) private _platformPipes: Type[]) {}
getMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
var meta = this._cache.get(directiveType);
getDirectiveMetadata(directiveType: Type): cpl.CompileDirectiveMetadata {
var meta = this._directiveCache.get(directiveType);
if (isBlank(meta)) {
var dirMeta = this._directiveResolver.resolve(directiveType);
var moduleUrl = null;
@@ -63,7 +67,23 @@ export class RuntimeMetadataResolver {
host: dirMeta.host,
lifecycleHooks: LIFECYCLE_HOOKS_VALUES.filter(hook => hasLifecycleHook(hook, directiveType))
});
this._cache.set(directiveType, meta);
this._directiveCache.set(directiveType, meta);
}
return meta;
}
getPipeMetadata(pipeType: Type): cpl.CompilePipeMetadata {
var meta = this._pipeCache.get(pipeType);
if (isBlank(meta)) {
var pipeMeta = this._pipeResolver.resolve(pipeType);
var moduleUrl = reflector.importUri(pipeType);
meta = new cpl.CompilePipeMetadata({
type: new cpl.CompileTypeMetadata(
{name: stringify(pipeType), moduleUrl: moduleUrl, runtime: pipeType}),
name: pipeMeta.name,
pure: pipeMeta.pure
});
this._pipeCache.set(pipeType, meta);
}
return meta;
}
@@ -72,13 +92,25 @@ export class RuntimeMetadataResolver {
var view = this._viewResolver.resolve(component);
var directives = flattenDirectives(view, this._platformDirectives);
for (var i = 0; i < directives.length; i++) {
if (!isValidDirective(directives[i])) {
if (!isValidType(directives[i])) {
throw new BaseException(
`Unexpected directive value '${stringify(directives[i])}' on the View of component '${stringify(component)}'`);
}
}
return directives.map(type => this.getMetadata(type));
return directives.map(type => this.getDirectiveMetadata(type));
}
getViewPipesMetadata(component: Type): cpl.CompilePipeMetadata[] {
var view = this._viewResolver.resolve(component);
var pipes = flattenPipes(view, this._platformPipes);
for (var i = 0; i < pipes.length; i++) {
if (!isValidType(pipes[i])) {
throw new BaseException(
`Unexpected piped value '${stringify(pipes[i])}' on the View of component '${stringify(component)}'`);
}
}
return pipes.map(type => this.getPipeMetadata(type));
}
}
@@ -93,6 +125,17 @@ function flattenDirectives(view: ViewMetadata, platformDirectives: any[]): Type[
return directives;
}
function flattenPipes(view: ViewMetadata, platformPipes: any[]): Type[] {
let pipes = [];
if (isPresent(platformPipes)) {
flattenArray(platformPipes, pipes);
}
if (isPresent(view.pipes)) {
flattenArray(view.pipes, pipes);
}
return pipes;
}
function flattenArray(tree: any[], out: Array<Type | any[]>): void {
for (var i = 0; i < tree.length; i++) {
var item = resolveForwardRef(tree[i]);
@@ -104,7 +147,7 @@ function flattenArray(tree: any[], out: Array<Type | any[]>): void {
}
}
function isValidDirective(value: Type): boolean {
function isValidType(value: Type): boolean {
return isPresent(value) && (value instanceof Type);
}
@@ -10,6 +10,10 @@ export function moduleRef(moduleUrl): string {
* Represents generated source code with module references. Internal to the Angular compiler.
*/
export class SourceModule {
static getSourceWithoutImports(sourceWithModuleRefs: string): string {
return StringWrapper.replaceAllMapped(sourceWithModuleRefs, MODULE_REGEXP, (match) => '');
}
constructor(public moduleUrl: string, public sourceWithModuleRefs: string) {}
getSourceWithImports(): SourceWithImports {
@@ -14,7 +14,10 @@ import {
MODULE_SUFFIX
} from './util';
import {Injectable} from 'angular2/src/core/di';
import {COMPONENT_VARIABLE, HOST_ATTR, CONTENT_ATTR} from 'angular2/src/core/render/view_factory';
const COMPONENT_VARIABLE = '%COMP%';
const HOST_ATTR = `_nghost-${COMPONENT_VARIABLE}`;
const CONTENT_ATTR = `_ngcontent-${COMPONENT_VARIABLE}`;
@Injectable()
export class StyleCompiler {
File diff suppressed because it is too large Load Diff
@@ -5,10 +5,11 @@ import {CONST_EXPR} from 'angular2/src/facade/lang';
import {BaseException} from 'angular2/src/facade/exceptions';
import {Parser, AST, ASTWithSource} from 'angular2/src/core/change_detection/change_detection';
import {TemplateBinding} from 'angular2/src/core/change_detection/parser/ast';
import {CompileDirectiveMetadata} from './directive_metadata';
import {CompileDirectiveMetadata, CompilePipeMetadata} from './directive_metadata';
import {HtmlParser} from './html_parser';
import {splitNsName} from './html_tags';
import {ParseSourceSpan, ParseError, ParseLocation} from './parse_util';
import {RecursiveAstVisitor, BindingPipe} from 'angular2/src/core/change_detection/parser/ast';
import {
@@ -88,9 +89,10 @@ export class TemplateParser {
private _htmlParser: HtmlParser,
@Optional() @Inject(TEMPLATE_TRANSFORMS) public transforms: TemplateAstVisitor[]) {}
parse(template: string, directives: CompileDirectiveMetadata[],
parse(template: string, directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
templateUrl: string): TemplateAst[] {
var parseVisitor = new TemplateParseVisitor(directives, this._exprParser, this._schemaRegistry);
var parseVisitor =
new TemplateParseVisitor(directives, pipes, this._exprParser, this._schemaRegistry);
var htmlAstWithErrors = this._htmlParser.parse(template, templateUrl);
var result = htmlVisitAll(parseVisitor, htmlAstWithErrors.rootNodes, EMPTY_COMPONENT);
var errors: ParseError[] = htmlAstWithErrors.errors.concat(parseVisitor.errors);
@@ -111,9 +113,10 @@ class TemplateParseVisitor implements HtmlAstVisitor {
errors: TemplateParseError[] = [];
directivesIndex = new Map<CompileDirectiveMetadata, number>();
ngContentCount: number = 0;
pipesByName: Map<string, CompilePipeMetadata>;
constructor(directives: CompileDirectiveMetadata[], private _exprParser: Parser,
private _schemaRegistry: ElementSchemaRegistry) {
constructor(directives: CompileDirectiveMetadata[], pipes: CompilePipeMetadata[],
private _exprParser: Parser, private _schemaRegistry: ElementSchemaRegistry) {
this.selectorMatcher = new SelectorMatcher();
ListWrapper.forEachWithIndex(directives,
(directive: CompileDirectiveMetadata, index: number) => {
@@ -121,6 +124,8 @@ class TemplateParseVisitor implements HtmlAstVisitor {
this.selectorMatcher.addSelectables(selector, directive);
this.directivesIndex.set(directive, index);
});
this.pipesByName = new Map<string, CompilePipeMetadata>();
pipes.forEach(pipe => this.pipesByName.set(pipe.name, pipe));
}
private _reportError(message: string, sourceSpan: ParseSourceSpan) {
@@ -130,7 +135,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
private _parseInterpolation(value: string, sourceSpan: ParseSourceSpan): ASTWithSource {
var sourceInfo = sourceSpan.start.toString();
try {
return this._exprParser.parseInterpolation(value, sourceInfo);
var ast = this._exprParser.parseInterpolation(value, sourceInfo);
this._checkPipes(ast, sourceSpan);
return ast;
} catch (e) {
this._reportError(`${e}`, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
@@ -140,7 +147,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
private _parseAction(value: string, sourceSpan: ParseSourceSpan): ASTWithSource {
var sourceInfo = sourceSpan.start.toString();
try {
return this._exprParser.parseAction(value, sourceInfo);
var ast = this._exprParser.parseAction(value, sourceInfo);
this._checkPipes(ast, sourceSpan);
return ast;
} catch (e) {
this._reportError(`${e}`, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
@@ -150,7 +159,9 @@ class TemplateParseVisitor implements HtmlAstVisitor {
private _parseBinding(value: string, sourceSpan: ParseSourceSpan): ASTWithSource {
var sourceInfo = sourceSpan.start.toString();
try {
return this._exprParser.parseBinding(value, sourceInfo);
var ast = this._exprParser.parseBinding(value, sourceInfo);
this._checkPipes(ast, sourceSpan);
return ast;
} catch (e) {
this._reportError(`${e}`, sourceSpan);
return this._exprParser.wrapLiteralPrimitive('ERROR', sourceInfo);
@@ -160,13 +171,31 @@ class TemplateParseVisitor implements HtmlAstVisitor {
private _parseTemplateBindings(value: string, sourceSpan: ParseSourceSpan): TemplateBinding[] {
var sourceInfo = sourceSpan.start.toString();
try {
return this._exprParser.parseTemplateBindings(value, sourceInfo);
var bindings = this._exprParser.parseTemplateBindings(value, sourceInfo);
bindings.forEach((binding) => {
if (isPresent(binding.expression)) {
this._checkPipes(binding.expression, sourceSpan);
}
});
return bindings;
} catch (e) {
this._reportError(`${e}`, sourceSpan);
return [];
}
}
private _checkPipes(ast: ASTWithSource, sourceSpan: ParseSourceSpan) {
if (isPresent(ast)) {
var collector = new PipeCollector();
ast.visit(collector);
collector.pipes.forEach((pipeName) => {
if (!this.pipesByName.has(pipeName)) {
this._reportError(`The pipe '${pipeName}' could not be found`, sourceSpan);
}
});
}
}
visitText(ast: HtmlTextAst, component: Component): any {
var ngContentIndex = component.findNgContentIndex(TEXT_CSS_SELECTOR);
var expr = this._parseInterpolation(ast.value, ast.sourceSpan);
@@ -714,3 +743,14 @@ function createElementCssSelector(elementName: string, matchableAttrs: string[][
var EMPTY_COMPONENT = new Component(new SelectorMatcher(), null);
var NON_BINDABLE_VISITOR = new NonBindableVisitor();
export class PipeCollector extends RecursiveAstVisitor {
pipes: Set<string> = new Set<string>();
visitPipe(ast: BindingPipe): any {
this.pipes.add(ast.name);
ast.exp.visit(this);
this.visitAll(ast.args);
return null;
}
}
+93 -3
View File
@@ -1,4 +1,11 @@
import {IS_DART, StringWrapper, isBlank} from 'angular2/src/facade/lang';
import {
IS_DART,
StringWrapper,
isBlank,
isPresent,
isString,
isArray
} from 'angular2/src/facade/lang';
var CAMEL_CASE_REGEXP = /([A-Z])/g;
var DASH_CASE_REGEXP = /-([a-z])/g;
@@ -7,6 +14,8 @@ var DOUBLE_QUOTE_ESCAPE_STRING_RE = /"|\\|\n|\r|\$/g;
export var MODULE_SUFFIX = IS_DART ? '.dart' : '.js';
export var CONST_VAR = IS_DART ? 'const' : 'var';
export function camelCaseToDashCase(input: string): string {
return StringWrapper.replaceAllMapped(input, CAMEL_CASE_REGEXP,
(m) => { return '-' + m[1].toLowerCase(); });
@@ -63,12 +72,19 @@ export function codeGenConstConstructorCall(name: string): string {
export function codeGenValueFn(params: string[], value: string, fnName: string = ''): string {
if (IS_DART) {
return `${fnName}(${params.join(',')}) => ${value}`;
return `${codeGenFnHeader(params, fnName)} => ${value}`;
} else {
return `function ${fnName}(${params.join(',')}) { return ${value}; }`;
return `${codeGenFnHeader(params, fnName)} { return ${value}; }`;
}
}
export function codeGenFnHeader(params: string[], fnName: string = ''): string {
if (IS_DART) {
return `${fnName}(${params.join(',')})`;
} else {
return `function ${fnName}(${params.join(',')})`;
}
}
export function codeGenToString(expr: string): string {
if (IS_DART) {
return `'\${${expr}}'`;
@@ -86,3 +102,77 @@ export function splitAtColon(input: string, defaultValues: string[]): string[] {
return defaultValues;
}
}
export class Statement {
constructor(public statement: string) {}
}
export class Expression {
constructor(public expression: string, public isArray = false) {}
}
export function escapeValue(value: any): string {
if (value instanceof Expression) {
return value.expression;
} else if (isString(value)) {
return escapeSingleQuoteString(value);
} else if (isBlank(value)) {
return 'null';
} else {
return `${value}`;
}
}
export function codeGenArray(data: any[]): string {
return `[${data.map(escapeValue).join(',')}]`;
}
export function codeGenFlatArray(values: any[]): string {
var result = '([';
var isFirstArrayEntry = true;
var concatFn = IS_DART ? '.addAll' : 'concat';
for (var i = 0; i < values.length; i++) {
var value = values[i];
if (value instanceof Expression && (<Expression>value).isArray) {
result += `]).${concatFn}(${value.expression}).${concatFn}([`;
isFirstArrayEntry = true;
} else {
if (!isFirstArrayEntry) {
result += ',';
}
isFirstArrayEntry = false;
result += escapeValue(value);
}
}
result += '])';
return result;
}
export function codeGenStringMap(keyValueArray: any[][]): string {
return `{${keyValueArray.map(codeGenKeyValue).join(',')}}`;
}
function codeGenKeyValue(keyValue: any[]): string {
return `${escapeValue(keyValue[0])}:${escapeValue(keyValue[1])}`;
}
export function addAll(source: any[], target: any[]) {
for (var i = 0; i < source.length; i++) {
target.push(source[i]);
}
}
export function flattenArray(source: any[], target: any[]): any[] {
if (isPresent(source)) {
for (var i = 0; i < source.length; i++) {
var item = source[i];
if (isArray(item)) {
flattenArray(item, target);
} else {
target.push(item);
}
}
}
return target;
}
File diff suppressed because it is too large Load Diff
@@ -11,13 +11,11 @@ import {
KeyValueDiffers,
defaultKeyValueDiffers
} from './change_detection/change_detection';
import {AppViewPool, APP_VIEW_POOL_CAPACITY} from './linker/view_pool';
import {ResolvedMetadataCache} from 'angular2/src/core/linker/resolved_metadata_cache';
import {AppViewManager} from './linker/view_manager';
import {AppViewManager_} from "./linker/view_manager";
import {AppViewManagerUtils} from './linker/view_manager_utils';
import {ViewResolver} from './linker/view_resolver';
import {AppViewListener} from './linker/view_listener';
import {ProtoViewFactory} from './linker/proto_view_factory';
import {DirectiveResolver} from './linker/directive_resolver';
import {PipeResolver} from './linker/pipe_resolver';
import {Compiler} from './linker/compiler';
@@ -32,12 +30,9 @@ import {DynamicComponentLoader_} from "./linker/dynamic_component_loader";
export const APPLICATION_COMMON_PROVIDERS: Array<Type | Provider | any[]> = CONST_EXPR([
new Provider(Compiler, {useClass: Compiler_}),
APP_ID_RANDOM_PROVIDER,
AppViewPool,
new Provider(APP_VIEW_POOL_CAPACITY, {useValue: 10000}),
ResolvedMetadataCache,
new Provider(AppViewManager, {useClass: AppViewManager_}),
AppViewManagerUtils,
AppViewListener,
ProtoViewFactory,
ViewResolver,
new Provider(IterableDiffers, {useValue: defaultIterableDiffers}),
new Provider(KeyValueDiffers, {useValue: defaultKeyValueDiffers}),
+7 -6
View File
@@ -33,11 +33,11 @@ import {
ExceptionHandler,
unimplemented
} from 'angular2/src/facade/exceptions';
import {internalView} from 'angular2/src/core/linker/view_ref';
import {Console} from 'angular2/src/core/console';
import {wtfLeave, wtfCreateScope, WtfScopeFn} from './profile/profile';
import {ChangeDetectorRef} from 'angular2/src/core/change_detection/change_detector_ref';
import {lockMode} from 'angular2/src/facade/lang';
import {ElementRef_} from 'angular2/src/core/linker/element_ref';
/**
* Construct providers specific to an individual root component.
@@ -56,10 +56,10 @@ function _componentProviders(appComponentType: Type): Array<Type | Provider | an
() => { appRef._unloadComponent(ref); })
.then((componentRef) => {
ref = componentRef;
if (isPresent(componentRef.location.nativeElement)) {
var testability = injector.getOptional(Testability);
if (isPresent(testability)) {
injector.get(TestabilityRegistry)
.registerApplication(componentRef.location.nativeElement,
injector.get(Testability));
.registerApplication(componentRef.location.nativeElement, testability);
}
return componentRef;
});
@@ -439,7 +439,7 @@ export class ApplicationRef_ extends ApplicationRef {
/** @internal */
_loadComponent(ref): void {
var appChangeDetector = internalView(ref.hostView).changeDetector;
var appChangeDetector = (<ElementRef_>ref.location).internalElement.parentView.changeDetector;
this._changeDetectorRefs.push(appChangeDetector.ref);
this.tick();
this._rootComponents.push(ref);
@@ -451,7 +451,8 @@ export class ApplicationRef_ extends ApplicationRef {
if (!ListWrapper.contains(this._rootComponents, ref)) {
return;
}
this.unregisterChangeDetector(internalView(ref.hostView).changeDetector.ref);
this.unregisterChangeDetector(
(<ElementRef_>ref.location).internalElement.parentView.changeDetector.ref);
ListWrapper.remove(this._rootComponents, ref);
}
@@ -8,7 +8,9 @@ import {Pipes} from './pipes';
import {
ChangeDetectionError,
ExpressionChangedAfterItHasBeenCheckedException,
DehydratedException
DehydratedException,
EventEvaluationErrorContext,
EventEvaluationError
} from './exceptions';
import {BindingTarget} from './binding_record';
import {Locals} from './parser/locals';
@@ -43,9 +45,12 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
subscriptions: any[];
streams: any[];
constructor(public id: string, public dispatcher: ChangeDispatcher,
public numberOfPropertyProtoRecords: number, public bindingTargets: BindingTarget[],
public directiveIndices: DirectiveIndex[], public strategy: ChangeDetectionStrategy) {
dispatcher: ChangeDispatcher;
constructor(public id: string, public numberOfPropertyProtoRecords: number,
public bindingTargets: BindingTarget[], public directiveIndices: DirectiveIndex[],
public strategy: ChangeDetectionStrategy) {
this.ref = new ChangeDetectorRef_(this);
}
@@ -65,10 +70,24 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
remove(): void { this.parent.removeContentChild(this); }
handleEvent(eventName: string, elIndex: number, locals: Locals): boolean {
var res = this.handleEventInternal(eventName, elIndex, locals);
this.markPathToRootAsCheckOnce();
return res;
handleEvent(eventName: string, elIndex: number, event: any): boolean {
if (!this.hydrated()) {
return true;
}
try {
var locals = new Map<string, any>();
locals.set('$event', event);
var res = !this.handleEventInternal(eventName, elIndex, new Locals(this.locals, locals));
this.markPathToRootAsCheckOnce();
return res;
} catch (e) {
var c = this.dispatcher.getDebugContext(null, elIndex, null);
var context = isPresent(c) ?
new EventEvaluationErrorContext(c.element, c.componentElement, c.context,
c.locals, c.injector) :
null;
throw new EventEvaluationError(eventName, e, e.stack, context);
}
}
handleEventInternal(eventName: string, elIndex: number, locals: Locals): boolean { return false; }
@@ -133,7 +152,8 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
// This method is not intended to be overridden. Subclasses should instead provide an
// implementation of `hydrateDirectives`.
hydrate(context: T, locals: Locals, directives: any, pipes: Pipes): void {
hydrate(context: T, locals: Locals, dispatcher: ChangeDispatcher, pipes: Pipes): void {
this.dispatcher = dispatcher;
this.mode = ChangeDetectionUtil.changeDetectionMode(this.strategy);
this.context = context;
@@ -143,12 +163,12 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
this.locals = locals;
this.pipes = pipes;
this.hydrateDirectives(directives);
this.hydrateDirectives(dispatcher);
this.state = ChangeDetectorState.NeverChecked;
}
// Subclasses should override this method to hydrate any directives.
hydrateDirectives(directives: any): void {}
hydrateDirectives(dispatcher: ChangeDispatcher): void {}
// This method is not intended to be overridden. Subclasses should instead provide an
// implementation of `dehydrateDirectives`.
@@ -160,6 +180,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
this._unsubsribeFromObservables();
}
this.dispatcher = null;
this.context = null;
this.locals = null;
this.pipes = null;
@@ -171,6 +192,19 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
hydrated(): boolean { return isPresent(this.context); }
destroyRecursive(): void {
this.dispatcher.notifyOnDestroy();
this.dehydrate();
var children = this.contentChildren;
for (var i = 0; i < children.length; i++) {
children[i].destroyRecursive();
}
children = this.viewChildren;
for (var i = 0; i < children.length; i++) {
children[i].destroyRecursive();
}
}
afterContentLifecycleCallbacks(): void {
this.dispatcher.notifyAfterContentChecked();
this.afterContentLifecycleCallbacksInternal();
@@ -298,7 +332,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
private _throwError(exception: any, stack: any): void {
var error;
try {
var c = this.dispatcher.getDebugContext(this._currentBinding().elementIndex, null);
var c = this.dispatcher.getDebugContext(null, this._currentBinding().elementIndex, null);
var context = isPresent(c) ? new _Context(c.element, c.componentElement, c.context, c.locals,
c.injector, this._currentBinding().debug) :
null;
@@ -66,8 +66,8 @@ export class ChangeDetectorJITGenerator {
generate(): Function {
var factorySource = `
${this.generateSource()}
return function(dispatcher) {
return new ${this.typeName}(dispatcher);
return function() {
return new ${this.typeName}();
}
`;
return new Function(this.abstractChangeDetectorVarName, this.changeDetectionUtilVarName,
@@ -77,9 +77,9 @@ export class ChangeDetectorJITGenerator {
generateSource(): string {
return `
var ${this.typeName} = function ${this.typeName}(dispatcher) {
var ${this.typeName} = function ${this.typeName}() {
${this.abstractChangeDetectorVarName}.call(
this, ${JSON.stringify(this.id)}, dispatcher, ${this.records.length},
this, ${JSON.stringify(this.id)}, ${this.records.length},
${this.typeName}.gen_propertyBindingTargets, ${this.typeName}.gen_directiveIndices,
${codify(this.changeDetectionStrategy)});
this.dehydrateDirectives(false);
@@ -199,13 +199,14 @@ export class ChangeDetectorJITGenerator {
/** @internal */
_maybeGenDehydrateDirectives(): string {
var destroyPipesCode = this._names.genPipeOnDestroy();
if (destroyPipesCode) {
destroyPipesCode = `if (destroyPipes) { ${destroyPipesCode} }`;
}
var destroyDirectivesCode = this._logic.genDirectivesOnDestroy(this.directiveRecords);
var dehydrateFieldsCode = this._names.genDehydrateFields();
if (!destroyPipesCode && !dehydrateFieldsCode) return '';
if (!destroyPipesCode && !destroyDirectivesCode && !dehydrateFieldsCode) return '';
return `${this.typeName}.prototype.dehydrateDirectives = function(destroyPipes) {
${destroyPipesCode}
if (destroyPipes) {
${destroyPipesCode}
${destroyDirectivesCode}
}
${dehydrateFieldsCode}
}`;
}
@@ -205,4 +205,4 @@ export class ChangeDetectorRef_ extends ChangeDetectorRef {
this._cd.mode = ChangeDetectionStrategy.CheckAlways;
this.markForCheck();
}
}
}
@@ -155,17 +155,49 @@ export class CodegenLogicUtil {
var res = [];
for (var i = 0; i < directiveRecords.length; ++i) {
var r = directiveRecords[i];
res.push(`${this._names.getDirectiveName(r.directiveIndex)} = ${this._genReadDirective(i)};`);
var dirVarName = this._names.getDirectiveName(r.directiveIndex);
res.push(`${dirVarName} = ${this._genReadDirective(i)};`);
if (isPresent(r.outputs)) {
r.outputs.forEach(output => {
var eventHandlerExpr = this._genEventHandler(r.directiveIndex.elementIndex, output[1]);
if (IS_DART) {
res.push(`${dirVarName}.${output[0]}.listen(${eventHandlerExpr});`);
} else {
res.push(`${dirVarName}.${output[0]}.subscribe({next: ${eventHandlerExpr}});`);
}
});
}
}
return res.join("\n");
}
genDirectivesOnDestroy(directiveRecords: DirectiveRecord[]): string {
var res = [];
for (var i = 0; i < directiveRecords.length; ++i) {
var r = directiveRecords[i];
if (r.callOnDestroy) {
var dirVarName = this._names.getDirectiveName(r.directiveIndex);
res.push(`${dirVarName}.ngOnDestroy();`);
}
}
return res.join("\n");
}
private _genEventHandler(boundElementIndex: number, eventName: string): string {
if (IS_DART) {
return `(event) => this.handleEvent('${eventName}', ${boundElementIndex}, event)`;
} else {
return `(function(event) { return this.handleEvent('${eventName}', ${boundElementIndex}, event); }).bind(this)`;
}
}
private _genReadDirective(index: number) {
var directiveExpr = `this.getDirectiveFor(directives, ${index})`;
// This is an experimental feature. Works only in Dart.
if (this._changeDetection === ChangeDetectionStrategy.OnPushObserve) {
return `this.observeDirective(this.getDirectiveFor(directives, ${index}), ${index})`;
return `this.observeDirective(${directiveExpr}, ${index})`;
} else {
return `this.getDirectiveFor(directives, ${index})`;
return directiveExpr;
}
}
@@ -16,10 +16,14 @@ export class DirectiveRecord {
callOnChanges: boolean;
callDoCheck: boolean;
callOnInit: boolean;
callOnDestroy: boolean;
changeDetection: ChangeDetectionStrategy;
// array of [emitter property name, eventName]
outputs: string[][];
constructor({directiveIndex, callAfterContentInit, callAfterContentChecked, callAfterViewInit,
callAfterViewChecked, callOnChanges, callDoCheck, callOnInit, changeDetection}: {
callAfterViewChecked, callOnChanges, callDoCheck, callOnInit, callOnDestroy,
changeDetection, outputs}: {
directiveIndex?: DirectiveIndex,
callAfterContentInit?: boolean,
callAfterContentChecked?: boolean,
@@ -28,7 +32,9 @@ export class DirectiveRecord {
callOnChanges?: boolean,
callDoCheck?: boolean,
callOnInit?: boolean,
changeDetection?: ChangeDetectionStrategy
callOnDestroy?: boolean,
changeDetection?: ChangeDetectionStrategy,
outputs?: string[][]
} = {}) {
this.directiveIndex = directiveIndex;
this.callAfterContentInit = normalizeBool(callAfterContentInit);
@@ -38,7 +44,9 @@ export class DirectiveRecord {
this.callAfterViewChecked = normalizeBool(callAfterViewChecked);
this.callDoCheck = normalizeBool(callDoCheck);
this.callOnInit = normalizeBool(callOnInit);
this.callOnDestroy = normalizeBool(callOnDestroy);
this.changeDetection = changeDetection;
this.outputs = outputs;
}
isDefaultChangeDetection(): boolean {
@@ -11,21 +11,21 @@ import {ChangeDispatcher, ChangeDetectorGenConfig} from './interfaces';
import {ChangeDetectionUtil, SimpleChange} from './change_detection_util';
import {ChangeDetectionStrategy, ChangeDetectorState} from './constants';
import {ProtoRecord, RecordType} from './proto_record';
import {reflector} from 'angular2/src/core/reflection/reflection';
import {ObservableWrapper} from 'angular2/src/facade/async';
export class DynamicChangeDetector extends AbstractChangeDetector<any> {
values: any[];
changes: any[];
localPipes: any[];
prevContexts: any[];
directives: any = null;
constructor(id: string, dispatcher: ChangeDispatcher, numberOfPropertyProtoRecords: number,
constructor(id: string, numberOfPropertyProtoRecords: number,
propertyBindingTargets: BindingTarget[], directiveIndices: DirectiveIndex[],
strategy: ChangeDetectionStrategy, private _records: ProtoRecord[],
private _eventBindings: EventBinding[], private _directiveRecords: DirectiveRecord[],
private _genConfig: ChangeDetectorGenConfig) {
super(id, dispatcher, numberOfPropertyProtoRecords, propertyBindingTargets, directiveIndices,
strategy);
super(id, numberOfPropertyProtoRecords, propertyBindingTargets, directiveIndices, strategy);
var len = _records.length + 1;
this.values = ListWrapper.createFixedSize(len);
this.localPipes = ListWrapper.createFixedSize(len);
@@ -104,24 +104,41 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
return this._eventBindings.filter(eb => eb.eventName == eventName && eb.elIndex === elIndex);
}
hydrateDirectives(directives: any): void {
hydrateDirectives(dispatcher: ChangeDispatcher): void {
this.values[0] = this.context;
this.directives = directives;
this.dispatcher = dispatcher;
if (this.strategy === ChangeDetectionStrategy.OnPushObserve) {
for (var i = 0; i < this.directiveIndices.length; ++i) {
var index = this.directiveIndices[i];
super.observeDirective(directives.getDirectiveFor(index), i);
super.observeDirective(this._getDirectiveFor(index), i);
}
}
for (var i = 0; i < this._directiveRecords.length; ++i) {
var r = this._directiveRecords[i];
if (isPresent(r.outputs)) {
r.outputs.forEach(output => {
var eventHandler =
<any>this._createEventHandler(r.directiveIndex.elementIndex, output[1]);
var directive = this._getDirectiveFor(r.directiveIndex);
var getter = reflector.getter(output[0]);
ObservableWrapper.subscribe(getter(directive), eventHandler);
});
}
}
}
private _createEventHandler(boundElementIndex: number, eventName: string): Function {
return (event) => this.handleEvent(eventName, boundElementIndex, event);
}
dehydrateDirectives(destroyPipes: boolean) {
if (destroyPipes) {
this._destroyPipes();
this._destroyDirectives();
}
this.values[0] = null;
this.directives = null;
ListWrapper.fill(this.values, ChangeDetectionUtil.uninitialized, 1);
ListWrapper.fill(this.changes, false);
ListWrapper.fill(this.localPipes, null);
@@ -137,6 +154,16 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
}
}
/** @internal */
_destroyDirectives() {
for (var i = 0; i < this._directiveRecords.length; ++i) {
var record = this._directiveRecords[i];
if (record.callOnDestroy) {
this._getDirectiveFor(record.directiveIndex).ngOnDestroy();
}
}
}
checkNoChanges(): void { this.runDetectChanges(true); }
detectChangesInRecordsInternal(throwOnChange: boolean) {
@@ -241,12 +268,14 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
}
/** @internal */
private _getDirectiveFor(directiveIndex) {
return this.directives.getDirectiveFor(directiveIndex);
private _getDirectiveFor(directiveIndex: DirectiveIndex) {
return this.dispatcher.getDirectiveFor(directiveIndex);
}
/** @internal */
private _getDetectorFor(directiveIndex) { return this.directives.getDetectorFor(directiveIndex); }
private _getDetectorFor(directiveIndex: DirectiveIndex) {
return this.dispatcher.getDetectorFor(directiveIndex);
}
/** @internal */
private _check(proto: ProtoRecord, throwOnChange: boolean, values: any[],

Some files were not shown because too many files have changed in this diff Show More