Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions modules/angular2/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export {
} from './src/core/metadata';

export {
AfterContentInit,
AfterContentChecked,
AfterViewInit,
AfterViewChecked,
OnChanges,
OnDestroy,
OnInit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,19 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
this.mode === ChangeDetectionStrategy.Checked)
return;
var s = _scope_check(this.id, throwOnChange);

this.detectChangesInRecords(throwOnChange);

this._detectChangesInLightDomChildren(throwOnChange);
if (throwOnChange === false) this.callAfterContentChecked();
if (!throwOnChange) this.afterContentLifecycleCallbacks();

this._detectChangesInShadowDomChildren(throwOnChange);
if (!throwOnChange) this.afterViewLifecycleCallbacks();

if (this.mode === ChangeDetectionStrategy.CheckOnce)
this.mode = ChangeDetectionStrategy.Checked;

this.alreadyChecked = true;
wtfLeave(s);
}

Expand Down Expand Up @@ -156,7 +163,19 @@ export class AbstractChangeDetector<T> implements ChangeDetector {

hydrated(): boolean { return this.context !== null; }

callAfterContentChecked(): void { this.dispatcher.notifyAfterContentChecked(); }
afterContentLifecycleCallbacks(): void {
this.dispatcher.notifyAfterContentChecked();
this.afterContentLifecycleCallbacksInternal();
}

afterContentLifecycleCallbacksInternal(): void {}

afterViewLifecycleCallbacks(): void {
this.dispatcher.notifyAfterViewChecked();
this.afterViewLifecycleCallbacksInternal();
}

afterViewLifecycleCallbacksInternal(): void {}

_detectChangesInLightDomChildren(throwOnChange: boolean): void {
var c = this.lightDomChildren;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,23 +63,23 @@ export class ChangeDetectorJITGenerator {
var ${CHANGES_LOCAL} = null;

${this.records.map((r) => this._genRecord(r)).join("\n")}

${this._names.getAlreadyCheckedName()} = true;
}

${this._maybeGenHandleEventInternal()}

${this._genCheckNoChanges()}

${this._maybeGenCallAfterContentChecked()}
${this._maybeGenAfterContentLifecycleCallbacks()}

${this._maybeGenAfterViewLifecycleCallbacks()}

${this._maybeGenHydrateDirectives()}

${this._maybeGenDehydrateDirectives()}

${this._genPropertyBindingTargets()};
${this._genPropertyBindingTargets()}

${this._genDirectiveIndices()};
${this._genDirectiveIndices()}

return function(dispatcher) {
return new ${this._typeName}(dispatcher);
Expand Down Expand Up @@ -172,23 +172,26 @@ export class ChangeDetectorJITGenerator {
}`;
}

_maybeGenCallAfterContentChecked(): string {
var notifications = [];
var dirs = this.directiveRecords;

// NOTE(kegluneq): Order is important!
for (var i = dirs.length - 1; i >= 0; --i) {
var dir = dirs[i];
if (dir.callAfterContentChecked) {
notifications.push(
`${this._names.getDirectiveName(dir.directiveIndex)}.afterContentChecked();`);
}
_maybeGenAfterContentLifecycleCallbacks(): string {
var notifications = this._logic.genContentLifecycleCallbacks(this.directiveRecords);
if (notifications.length > 0) {
var directiveNotifications = notifications.join("\n");
return `
${this._typeName}.prototype.afterContentLifecycleCallbacksInternal = function() {
${directiveNotifications}
}
`;
} else {
return '';
}
}

_maybeGenAfterViewLifecycleCallbacks(): string {
var notifications = this._logic.genViewLifecycleCallbacks(this.directiveRecords);
if (notifications.length > 0) {
var directiveNotifications = notifications.join("\n");
return `
${this._typeName}.prototype.callAfterContentChecked = function() {
${ABSTRACT_CHANGE_DETECTOR}.prototype.callAfterContentChecked.call(this);
${this._typeName}.prototype.afterViewLifecycleCallbacksInternal = function() {
${directiveNotifications}
}
`;
Expand Down
34 changes: 34 additions & 0 deletions modules/angular2/src/core/change_detection/codegen_logic_util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,38 @@ export class CodegenLogicUtil {
}
return res.join("\n");
}

genContentLifecycleCallbacks(directiveRecords: DirectiveRecord[]): string[] {
var res = [];
// NOTE(kegluneq): Order is important!
for (var i = directiveRecords.length - 1; i >= 0; --i) {
var dir = directiveRecords[i];
if (dir.callAfterContentInit) {
res.push(
`if(! ${this._names.getAlreadyCheckedName()}) ${this._names.getDirectiveName(dir.directiveIndex)}.afterContentInit();`);
}

if (dir.callAfterContentChecked) {
res.push(`${this._names.getDirectiveName(dir.directiveIndex)}.afterContentChecked();`);
}
}
return res;
}

genViewLifecycleCallbacks(directiveRecords: DirectiveRecord[]): string[] {
var res = [];
// NOTE(kegluneq): Order is important!
for (var i = directiveRecords.length - 1; i >= 0; --i) {
var dir = directiveRecords[i];
if (dir.callAfterViewInit) {
res.push(
`if(! ${this._names.getAlreadyCheckedName()}) ${this._names.getDirectiveName(dir.directiveIndex)}.afterViewInit();`);
}

if (dir.callAfterViewChecked) {
res.push(`${this._names.getDirectiveName(dir.directiveIndex)}.afterViewChecked();`);
}
}
return res;
}
}
13 changes: 11 additions & 2 deletions modules/angular2/src/core/change_detection/directive_record.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,33 @@ export class DirectiveIndex {

export class DirectiveRecord {
directiveIndex: DirectiveIndex;
callAfterContentInit: boolean;
callAfterContentChecked: boolean;
callAfterViewInit: boolean;
callAfterViewChecked: boolean;
callOnChanges: boolean;
callDoCheck: boolean;
callOnInit: boolean;
changeDetection: ChangeDetectionStrategy;

constructor({directiveIndex, callAfterContentChecked, callOnChanges, callDoCheck, callOnInit,
changeDetection}: {
constructor({directiveIndex, callAfterContentInit, callAfterContentChecked, callAfterViewInit,
callAfterViewChecked, callOnChanges, callDoCheck, callOnInit, changeDetection}: {
directiveIndex?: DirectiveIndex,
callAfterContentInit?: boolean,
callAfterContentChecked?: boolean,
callAfterViewInit?: boolean,
callAfterViewChecked?: boolean,
callOnChanges?: boolean,
callDoCheck?: boolean,
callOnInit?: boolean,
changeDetection?: ChangeDetectionStrategy
} = {}) {
this.directiveIndex = directiveIndex;
this.callAfterContentInit = normalizeBool(callAfterContentInit);
this.callAfterContentChecked = normalizeBool(callAfterContentChecked);
this.callOnChanges = normalizeBool(callOnChanges);
this.callAfterViewInit = normalizeBool(callAfterViewInit);
this.callAfterViewChecked = normalizeBool(callAfterViewChecked);
this.callDoCheck = normalizeBool(callDoCheck);
this.callOnInit = normalizeBool(callOnInit);
this.changeDetection = changeDetection;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,26 +159,40 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
isChanged = false;
}
}

this.alreadyChecked = true;
}

_firstInBinding(r: ProtoRecord): boolean {
var prev = ChangeDetectionUtil.protoByIndex(this.records, r.selfIndex - 1);
return isBlank(prev) || prev.bindingRecord !== r.bindingRecord;
}

callAfterContentChecked() {
super.callAfterContentChecked();
afterContentLifecycleCallbacksInternal() {
var dirs = this.directiveRecords;
for (var i = dirs.length - 1; i >= 0; --i) {
var dir = dirs[i];
if (dir.callAfterContentInit && !this.alreadyChecked) {
this._getDirectiveFor(dir.directiveIndex).afterContentInit();
}

if (dir.callAfterContentChecked) {
this._getDirectiveFor(dir.directiveIndex).afterContentChecked();
}
}
}

afterViewLifecycleCallbacksInternal() {
var dirs = this.directiveRecords;
for (var i = dirs.length - 1; i >= 0; --i) {
var dir = dirs[i];
if (dir.callAfterViewInit && !this.alreadyChecked) {
this._getDirectiveFor(dir.directiveIndex).afterViewInit();
}
if (dir.callAfterViewChecked) {
this._getDirectiveFor(dir.directiveIndex).afterViewChecked();
}
}
}

_updateDirectiveOrElement(change, bindingRecord) {
if (isBlank(bindingRecord.directiveRecord)) {
super.notifyDispatcher(change.currentValue);
Expand Down
1 change: 1 addition & 0 deletions modules/angular2/src/core/change_detection/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export interface ChangeDispatcher {
notifyOnBinding(bindingTarget: BindingTarget, value: any): void;
logBindingUpdate(bindingTarget: BindingTarget, value: any): void;
notifyAfterContentChecked(): void;
notifyAfterViewChecked(): void;
}

export interface ChangeDetector {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,14 @@ bool hasLifecycleHook(LifecycleEvent e, type, DirectiveMetadata annotation) {
interface = OnChanges;
} else if (e == LifecycleEvent.OnDestroy) {
interface = OnDestroy;
} else if (e == LifecycleEvent.AfterContentInit) {
interface = AfterContentInit;
} else if (e == LifecycleEvent.AfterContentChecked) {
interface = AfterContentChecked;
} else if (e == LifecycleEvent.AfterViewInit) {
interface = AfterViewInit;
} else if (e == LifecycleEvent.AfterViewChecked) {
interface = AfterViewChecked;
} else if (e == LifecycleEvent.DoCheck) {
interface = DoCheck;
} else if (e == LifecycleEvent.OnInit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ export function hasLifecycleHook(e: LifecycleEvent, type, annotation: DirectiveM
if (!(type instanceof Type)) return false;
var proto = (<any>type).prototype;
switch (e) {
case LifecycleEvent.AfterContentInit:
return !!proto.afterContentInit;
case LifecycleEvent.AfterContentChecked:
return !!proto.afterContentChecked;
case LifecycleEvent.AfterViewInit:
return !!proto.afterViewInit;
case LifecycleEvent.AfterViewChecked:
return !!proto.afterViewChecked;
case LifecycleEvent.OnChanges:
return !!proto.onChanges;
case LifecycleEvent.DoCheck:
Expand Down
43 changes: 23 additions & 20 deletions modules/angular2/src/core/compiler/element_injector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,38 +216,41 @@ export class DirectiveBinding extends ResolvedBinding {

get changeDetection() { return this.metadata.changeDetection; }

static createFromBinding(binding: Binding, ann: DirectiveMetadata): DirectiveBinding {
if (isBlank(ann)) {
ann = new DirectiveMetadata();
static createFromBinding(binding: Binding, meta: DirectiveMetadata): DirectiveBinding {
if (isBlank(meta)) {
meta = new DirectiveMetadata();
}

var rb = binding.resolve();
var deps = ListWrapper.map(rb.dependencies, DirectiveDependency.createFrom);
var resolvedBindings = isPresent(ann.bindings) ? Injector.resolve(ann.bindings) : [];
var resolvedViewBindings = ann instanceof ComponentMetadata && isPresent(ann.viewBindings) ?
Injector.resolve(ann.viewBindings) :
var resolvedBindings = isPresent(meta.bindings) ? Injector.resolve(meta.bindings) : [];
var resolvedViewBindings = meta instanceof ComponentMetadata && isPresent(meta.viewBindings) ?
Injector.resolve(meta.viewBindings) :
[];
var metadata = RenderDirectiveMetadata.create({
id: stringify(rb.key.token),
type: ann instanceof ComponentMetadata ? RenderDirectiveMetadata.COMPONENT_TYPE :
RenderDirectiveMetadata.DIRECTIVE_TYPE,
selector: ann.selector,
compileChildren: ann.compileChildren,
events: ann.events,
host: isPresent(ann.host) ? MapWrapper.createFromStringMap(ann.host) : null,
properties: ann.properties,
type: meta instanceof ComponentMetadata ? RenderDirectiveMetadata.COMPONENT_TYPE :
RenderDirectiveMetadata.DIRECTIVE_TYPE,
selector: meta.selector,
compileChildren: meta.compileChildren,
events: meta.events,
host: isPresent(meta.host) ? MapWrapper.createFromStringMap(meta.host) : null,
properties: meta.properties,
readAttributes: DirectiveBinding._readAttributes(deps),

callOnDestroy: hasLifecycleHook(LifecycleEvent.OnDestroy, rb.key.token, ann),
callOnChanges: hasLifecycleHook(LifecycleEvent.OnChanges, rb.key.token, ann),
callDoCheck: hasLifecycleHook(LifecycleEvent.DoCheck, rb.key.token, ann),
callOnInit: hasLifecycleHook(LifecycleEvent.OnInit, rb.key.token, ann),
callOnDestroy: hasLifecycleHook(LifecycleEvent.OnDestroy, rb.key.token, meta),
callOnChanges: hasLifecycleHook(LifecycleEvent.OnChanges, rb.key.token, meta),
callDoCheck: hasLifecycleHook(LifecycleEvent.DoCheck, rb.key.token, meta),
callOnInit: hasLifecycleHook(LifecycleEvent.OnInit, rb.key.token, meta),
callAfterContentInit: hasLifecycleHook(LifecycleEvent.AfterContentInit, rb.key.token, meta),
callAfterContentChecked:
hasLifecycleHook(LifecycleEvent.AfterContentChecked, rb.key.token, ann),
hasLifecycleHook(LifecycleEvent.AfterContentChecked, rb.key.token, meta),
callAfterViewInit: hasLifecycleHook(LifecycleEvent.AfterViewInit, rb.key.token, meta),
callAfterViewChecked: hasLifecycleHook(LifecycleEvent.AfterViewChecked, rb.key.token, meta),

changeDetection: ann instanceof ComponentMetadata ? ann.changeDetection : null,
changeDetection: meta instanceof ComponentMetadata ? meta.changeDetection : null,

exportAs: ann.exportAs
exportAs: meta.exportAs
});
return new DirectiveBinding(rb.key, rb.factory, deps, resolvedBindings, resolvedViewBindings,
metadata);
Expand Down
23 changes: 22 additions & 1 deletion modules/angular2/src/core/compiler/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,30 @@ export interface DoCheck { doCheck(): boolean; }
*/
export interface OnDestroy { onDestroy(): void; }

/**
* Defines lifecycle method
* {@link metadata/LifeCycleEvent#AfterContentInit `LifeCycleEvent.afterContentInit`}
* called when the bindings of all its content children have been checked the first time.
*/
export interface AfterContentInit { afterContentInit(): void; }

/**
* Defines lifecycle method
* {@link metadata/LifeCycleEvent#AfterContentChecked `LifeCycleEvent.afterContentChecked`}
* called when the bindings of all its view children have been changed.
* called when the bindings of all its content children have been checked.
*/
export interface AfterContentChecked { afterContentChecked(): void; }

/**
* Defines lifecycle method
* {@link metadata/LifeCycleEvent#AfterViewInit `LifeCycleEvent.afterViewInit`}
* called when the bindings of all its view children have been checked the first time.
*/
export interface AfterViewInit { afterViewInit(): void; }

/**
* Defines lifecycle method
* {@link metadata/LifeCycleEvent#AfterViewChecked `LifeCycleEvent.afterViewChecked`}
* called when the bindings of all its view children have been checked.
*/
export interface AfterViewChecked { afterViewChecked(): void; }
3 changes: 3 additions & 0 deletions modules/angular2/src/core/compiler/proto_view_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,10 @@ export class BindingRecordsCreator {
this._directiveRecordsMap.set(
id, new DirectiveRecord({
directiveIndex: new DirectiveIndex(boundElementIndex, directiveIndex),
callAfterContentInit: directiveMetadata.callAfterContentInit,
callAfterContentChecked: directiveMetadata.callAfterContentChecked,
callAfterViewInit: directiveMetadata.callAfterViewInit,
callAfterViewChecked: directiveMetadata.callAfterViewChecked,
callOnChanges: directiveMetadata.callOnChanges,
callDoCheck: directiveMetadata.callDoCheck,
callOnInit: directiveMetadata.callOnInit,
Expand Down
4 changes: 4 additions & 0 deletions modules/angular2/src/core/compiler/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@ export class AppView implements ChangeDispatcher, RenderEventDispatcher {
}
}

notifyAfterViewChecked(): void {
// required for query
}

getDirectiveFor(directive: DirectiveIndex): any {
var elementInjector = this.elementInjectors[this.elementOffset + directive.elementIndex];
return elementInjector.getDirectiveAtIndex(directive.directiveIndex);
Expand Down
Loading