feat(change_detection): added a directive lifecycle hook that is called after children are checked
This commit is contained in:
@ -42,11 +42,13 @@ export class AbstractChangeDetector extends ChangeDetector {
|
||||
|
||||
this.detectChangesInRecords(throwOnChange);
|
||||
this._detectChangesInChildren(throwOnChange);
|
||||
this.notifyOnAllChangesDone();
|
||||
|
||||
if (this.mode === CHECK_ONCE) this.mode = CHECKED;
|
||||
}
|
||||
|
||||
detectChangesInRecords(throwOnChange:boolean){}
|
||||
notifyOnAllChangesDone(){}
|
||||
|
||||
_detectChangesInChildren(throwOnChange:boolean) {
|
||||
var children = this.children;
|
||||
|
@ -1,7 +1,7 @@
|
||||
library change_detectoin.change_detection_jit_generator;
|
||||
|
||||
class ChangeDetectorJITGenerator {
|
||||
ChangeDetectorJITGenerator(typeName, records) {
|
||||
ChangeDetectorJITGenerator(typeName, records, directiveMementos) {
|
||||
}
|
||||
|
||||
generate() {
|
||||
|
@ -64,6 +64,7 @@ import {
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* ChangeDetector0.prototype.notifyOnAllChangesDone = function() {}
|
||||
*
|
||||
* ChangeDetector0.prototype.hydrate = function(context, locals) {
|
||||
* this.context = context;
|
||||
@ -96,31 +97,35 @@ var UTIL = "ChangeDetectionUtil";
|
||||
var DISPATCHER_ACCESSOR = "this.dispatcher";
|
||||
var PIPE_REGISTRY_ACCESSOR = "this.pipeRegistry";
|
||||
var PROTOS_ACCESSOR = "this.protos";
|
||||
var MEMENTOS_ACCESSOR = "this.directiveMementos";
|
||||
var CONTEXT_ACCESSOR = "this.context";
|
||||
var CHANGE_LOCAL = "change";
|
||||
var CHANGES_LOCAL = "changes";
|
||||
var LOCALS_ACCESSOR = "this.locals";
|
||||
var TEMP_LOCAL = "temp";
|
||||
|
||||
function typeTemplate(type:string, cons:string, detectChanges:string, setContext:string):string {
|
||||
function typeTemplate(type:string, cons:string, detectChanges:string,
|
||||
notifyOnAllChangesDone:string, setContext:string):string {
|
||||
return `
|
||||
${cons}
|
||||
${detectChanges}
|
||||
${notifyOnAllChangesDone}
|
||||
${setContext};
|
||||
|
||||
return function(dispatcher, pipeRegistry) {
|
||||
return new ${type}(dispatcher, pipeRegistry, protos);
|
||||
return new ${type}(dispatcher, pipeRegistry, protos, directiveMementos);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function constructorTemplate(type:string, fieldsDefinitions:string):string {
|
||||
return `
|
||||
var ${type} = function ${type}(dispatcher, pipeRegistry, protos) {
|
||||
var ${type} = function ${type}(dispatcher, pipeRegistry, protos, directiveMementos) {
|
||||
${ABSTRACT_CHANGE_DETECTOR}.call(this);
|
||||
${DISPATCHER_ACCESSOR} = dispatcher;
|
||||
${PIPE_REGISTRY_ACCESSOR} = pipeRegistry;
|
||||
${PROTOS_ACCESSOR} = protos;
|
||||
${MEMENTOS_ACCESSOR} = directiveMementos;
|
||||
${fieldsDefinitions}
|
||||
}
|
||||
|
||||
@ -157,6 +162,18 @@ ${type}.prototype.detectChangesInRecords = function(throwOnChange) {
|
||||
`;
|
||||
}
|
||||
|
||||
function notifyOnAllChangesDoneTemplate(type:string, body:string):string {
|
||||
return `
|
||||
${type}.prototype.notifyOnAllChangesDone = function() {
|
||||
${body}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
function onAllChangesDoneTemplate(index:number):string {
|
||||
return `${DISPATCHER_ACCESSOR}.onAllChangesDone(${MEMENTOS_ACCESSOR}[${index}]);`;
|
||||
}
|
||||
|
||||
|
||||
function bodyTemplate(localDefinitions:string, changeDefinitions:string, records:string):string {
|
||||
return `
|
||||
@ -247,14 +264,16 @@ function addSimpleChangeRecordTemplate(protoIndex:number, oldValue:string, newVa
|
||||
export class ChangeDetectorJITGenerator {
|
||||
typeName:string;
|
||||
records:List<ProtoRecord>;
|
||||
directiveMementos:List;
|
||||
localNames:List<String>;
|
||||
changeNames:List<String>;
|
||||
fieldNames:List<String>;
|
||||
pipeNames:List<String>;
|
||||
|
||||
constructor(typeName:string, records:List<ProtoRecord>) {
|
||||
constructor(typeName:string, records:List<ProtoRecord>, directiveMementos:List) {
|
||||
this.typeName = typeName;
|
||||
this.records = records;
|
||||
this.directiveMementos = directiveMementos;
|
||||
|
||||
this.localNames = this.getLocalNames(records);
|
||||
this.changeNames = this.getChangeNames(this.localNames);
|
||||
@ -284,8 +303,10 @@ export class ChangeDetectorJITGenerator {
|
||||
}
|
||||
|
||||
generate():Function {
|
||||
var text = typeTemplate(this.typeName, this.genConstructor(), this.genDetectChanges(), this.genHydrate());
|
||||
return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos', text)(AbstractChangeDetector, ChangeDetectionUtil, this.records);
|
||||
var text = typeTemplate(this.typeName, this.genConstructor(), this.genDetectChanges(),
|
||||
this.genNotifyOnAllChangesDone(), this.genHydrate());
|
||||
return new Function('AbstractChangeDetector', 'ChangeDetectionUtil', 'protos', 'directiveMementos', text)
|
||||
(AbstractChangeDetector, ChangeDetectionUtil, this.records, this.directiveMementos);
|
||||
}
|
||||
|
||||
genConstructor():string {
|
||||
@ -319,6 +340,20 @@ export class ChangeDetectorJITGenerator {
|
||||
return detectChangesTemplate(this.typeName, body);
|
||||
}
|
||||
|
||||
genNotifyOnAllChangesDone():string {
|
||||
var notifications = [];
|
||||
var mementos = this.directiveMementos;
|
||||
|
||||
for (var i = mementos.length - 1; i >= 0; --i) {
|
||||
var memento = mementos[i];
|
||||
if (memento.notifyOnAllChangesDone) {
|
||||
notifications.push(onAllChangesDoneTemplate(i));
|
||||
}
|
||||
}
|
||||
|
||||
return notifyOnAllChangesDoneTemplate(this.typeName, notifications.join(";\n"));
|
||||
}
|
||||
|
||||
genBody():string {
|
||||
var rec = this.records.map((r) => this.genRecord(r)).join("\n");
|
||||
return bodyTemplate(this.genLocalDefinitions(), this.genChangeDefinitions(), rec);
|
||||
|
@ -34,8 +34,9 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
prevContexts:List;
|
||||
|
||||
protos:List<ProtoRecord>;
|
||||
directiveMementos:List;
|
||||
|
||||
constructor(dispatcher:any, pipeRegistry:PipeRegistry, protoRecords:List<ProtoRecord>) {
|
||||
constructor(dispatcher:any, pipeRegistry:PipeRegistry, protoRecords:List<ProtoRecord>, directiveMementos:List) {
|
||||
super();
|
||||
this.dispatcher = dispatcher;
|
||||
this.pipeRegistry = pipeRegistry;
|
||||
@ -52,6 +53,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
this.locals = null;
|
||||
|
||||
this.protos = protoRecords;
|
||||
this.directiveMementos = directiveMementos;
|
||||
}
|
||||
|
||||
hydrate(context:any, locals:any) {
|
||||
@ -102,6 +104,16 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
}
|
||||
}
|
||||
|
||||
notifyOnAllChangesDone() {
|
||||
var mementos = this.directiveMementos;
|
||||
for (var i = mementos.length - 1; i >= 0; --i) {
|
||||
var memento = mementos[i];
|
||||
if (memento.notifyOnAllChangesDone) {
|
||||
this.dispatcher.onAllChangesDone(memento);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_check(proto:ProtoRecord) {
|
||||
try {
|
||||
if (proto.mode === RECORD_TYPE_PIPE || proto.mode === RECORD_TYPE_BINDING_PIPE) {
|
||||
|
@ -47,7 +47,7 @@ import {
|
||||
|
||||
export class ProtoChangeDetector {
|
||||
addAst(ast:AST, bindingMemento:any, directiveMemento:any = null){}
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List):ChangeDetector{
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveMemento:List):ChangeDetector{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -73,9 +73,9 @@ export class DynamicProtoChangeDetector extends ProtoChangeDetector {
|
||||
this._pipeRegistry = pipeRegistry;
|
||||
}
|
||||
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List) {
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveMementos:List) {
|
||||
this._createRecordsIfNecessary(bindingRecords, variableBindings);
|
||||
return new DynamicChangeDetector(dispatcher, this._pipeRegistry, this._records);
|
||||
return new DynamicChangeDetector(dispatcher, this._pipeRegistry, this._records, directiveMementos);
|
||||
}
|
||||
|
||||
_createRecordsIfNecessary(bindingRecords:List, variableBindings:List) {
|
||||
@ -100,12 +100,12 @@ export class JitProtoChangeDetector extends ProtoChangeDetector {
|
||||
this._factory = null;
|
||||
}
|
||||
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List) {
|
||||
this._createFactoryIfNecessary(bindingRecords, variableBindings);
|
||||
instantiate(dispatcher:any, bindingRecords:List, variableBindings:List, directiveMementos:List) {
|
||||
this._createFactoryIfNecessary(bindingRecords, variableBindings, directiveMementos);
|
||||
return this._factory(dispatcher, this._pipeRegistry);
|
||||
}
|
||||
|
||||
_createFactoryIfNecessary(bindingRecords:List, variableBindings:List) {
|
||||
_createFactoryIfNecessary(bindingRecords:List, variableBindings:List, directiveMementos:List) {
|
||||
if (isBlank(this._factory)) {
|
||||
var recordBuilder = new ProtoRecordBuilder();
|
||||
ListWrapper.forEach(bindingRecords, (r) => {
|
||||
@ -114,7 +114,7 @@ export class JitProtoChangeDetector extends ProtoChangeDetector {
|
||||
var c = _jitProtoChangeDetectorClassCounter++;
|
||||
var records = coalesce(recordBuilder.records);
|
||||
var typeName = `ChangeDetector${c}`;
|
||||
this._factory = new ChangeDetectorJITGenerator(typeName, records).generate();
|
||||
this._factory = new ChangeDetectorJITGenerator(typeName, records, directiveMementos).generate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user