feat(view): reimplemented property setters using change detection
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import {isPresent, isBlank} from 'angular2/src/facade/lang';
|
||||
import {SetterFn} from 'angular2/src/reflection/types';
|
||||
import {AST} from './parser/ast';
|
||||
import {DirectiveRecord} from './directive_record';
|
||||
import {DirectiveIndex, DirectiveRecord} from './directive_record';
|
||||
|
||||
const DIRECTIVE="directive";
|
||||
const ELEMENT="element";
|
||||
@ -11,14 +11,16 @@ export class BindingRecord {
|
||||
mode:string;
|
||||
ast:AST;
|
||||
|
||||
implicitReceiver:any; //number | DirectiveIndex
|
||||
elementIndex:number;
|
||||
propertyName:string;
|
||||
setter:SetterFn;
|
||||
|
||||
directiveRecord:DirectiveRecord;
|
||||
|
||||
constructor(mode:string, ast:AST, elementIndex:number, propertyName:string, setter:SetterFn, directiveRecord:DirectiveRecord) {
|
||||
constructor(mode:string, implicitReceiver:any, ast:AST, elementIndex:number, propertyName:string, setter:SetterFn, directiveRecord:DirectiveRecord) {
|
||||
this.mode = mode;
|
||||
this.implicitReceiver = implicitReceiver;
|
||||
this.ast = ast;
|
||||
|
||||
this.elementIndex = elementIndex;
|
||||
@ -49,14 +51,18 @@ export class BindingRecord {
|
||||
}
|
||||
|
||||
static createForDirective(ast:AST, propertyName:string, setter:SetterFn, directiveRecord:DirectiveRecord) {
|
||||
return new BindingRecord(DIRECTIVE, ast, 0, propertyName, setter, directiveRecord);
|
||||
return new BindingRecord(DIRECTIVE, 0, ast, 0, propertyName, setter, directiveRecord);
|
||||
}
|
||||
|
||||
static createForElement(ast:AST, elementIndex:number, propertyName:string) {
|
||||
return new BindingRecord(ELEMENT, ast, elementIndex, propertyName, null, null);
|
||||
return new BindingRecord(ELEMENT, 0, ast, elementIndex, propertyName, null, null);
|
||||
}
|
||||
|
||||
static createForHostProperty(directiveIndex:DirectiveIndex, ast:AST, propertyName:string) {
|
||||
return new BindingRecord(ELEMENT, directiveIndex, ast, directiveIndex.elementIndex, propertyName, null, null);
|
||||
}
|
||||
|
||||
static createForTextNode(ast:AST, elementIndex:number) {
|
||||
return new BindingRecord(TEXT_NODE, ast, elementIndex, null, null, null);
|
||||
return new BindingRecord(TEXT_NODE, 0, ast, elementIndex, null, null, null);
|
||||
}
|
||||
}
|
@ -3,7 +3,7 @@ import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/faca
|
||||
|
||||
import {AbstractChangeDetector} from './abstract_change_detector';
|
||||
import {ChangeDetectionUtil} from './change_detection_util';
|
||||
import {DirectiveRecord} from './directive_record';
|
||||
import {DirectiveIndex, DirectiveRecord} from './directive_record';
|
||||
|
||||
import {
|
||||
ProtoRecord,
|
||||
@ -81,12 +81,12 @@ function hydrateTemplate(type:string, mode:string, fieldDefinitions:string, pipe
|
||||
directiveFieldNames:List<String>, detectorFieldNames:List<String>):string {
|
||||
var directiveInit = "";
|
||||
for(var i = 0; i < directiveFieldNames.length; ++i) {
|
||||
directiveInit += `${directiveFieldNames[i]} = directives.getDirectiveFor(this.directiveRecords[${i}]);\n`;
|
||||
directiveInit += `${directiveFieldNames[i]} = directives.getDirectiveFor(this.directiveRecords[${i}].directiveIndex);\n`;
|
||||
}
|
||||
|
||||
var detectorInit = "";
|
||||
for(var i = 0; i < detectorFieldNames.length; ++i) {
|
||||
detectorInit += `${detectorFieldNames[i]} = directives.getDetectorFor(this.directiveRecords[${i}]);\n`;
|
||||
detectorInit += `${detectorFieldNames[i]} = directives.getDetectorFor(this.directiveRecords[${i}].directiveIndex);\n`;
|
||||
}
|
||||
|
||||
return `
|
||||
@ -313,18 +313,18 @@ export class ChangeDetectorJITGenerator {
|
||||
}
|
||||
|
||||
getDirectiveFieldNames():List<string> {
|
||||
return this.directiveRecords.map((d) => this.getDirective(d));
|
||||
return this.directiveRecords.map((d) => this.getDirective(d.directiveIndex));
|
||||
}
|
||||
|
||||
getDetectorFieldNames():List<string> {
|
||||
return this.directiveRecords.filter(r => r.isOnPushChangeDetection()).map((d) => this.getDetector(d));
|
||||
return this.directiveRecords.filter(r => r.isOnPushChangeDetection()).map((d) => this.getDetector(d.directiveIndex));
|
||||
}
|
||||
|
||||
getDirective(d:DirectiveRecord) {
|
||||
getDirective(d:DirectiveIndex) {
|
||||
return `this.directive_${d.name}`;
|
||||
}
|
||||
|
||||
getDetector(d:DirectiveRecord) {
|
||||
getDetector(d:DirectiveIndex) {
|
||||
return `this.detector_${d.name}`;
|
||||
}
|
||||
|
||||
@ -359,7 +359,7 @@ export class ChangeDetectorJITGenerator {
|
||||
for (var i = dirs.length - 1; i >= 0; --i) {
|
||||
var dir = dirs[i];
|
||||
if (dir.callOnAllChangesDone) {
|
||||
var directive = `this.directive_${dir.name}`;
|
||||
var directive = `this.directive_${dir.directiveIndex.name}`;
|
||||
notifications.push(onAllChangesDoneTemplate(directive));
|
||||
}
|
||||
}
|
||||
@ -425,7 +425,7 @@ export class ChangeDetectorJITGenerator {
|
||||
}
|
||||
|
||||
genUpdateCurrentValue(r:ProtoRecord):string {
|
||||
var context = this.localNames[r.contextIndex];
|
||||
var context = this.getContext(r);
|
||||
var newValue = this.localNames[r.selfIndex];
|
||||
var args = this.genArgs(r);
|
||||
|
||||
@ -463,6 +463,14 @@ export class ChangeDetectorJITGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
getContext(r:ProtoRecord):string {
|
||||
if (r.contextIndex == -1) {
|
||||
return this.getDirective(r.directiveIndex);
|
||||
} else {
|
||||
return this.localNames[r.contextIndex];
|
||||
}
|
||||
}
|
||||
|
||||
ifChangedGuard(r:ProtoRecord, body:string):string {
|
||||
return ifChangedGuardTemplate(r.args.map((a) => this.changeNames[a]), body);
|
||||
}
|
||||
@ -491,7 +499,7 @@ export class ChangeDetectorJITGenerator {
|
||||
|
||||
var br = r.bindingRecord;
|
||||
if (br.isDirective()) {
|
||||
var directiveProperty = `${this.getDirective(br.directiveRecord)}.${br.propertyName}`;
|
||||
var directiveProperty = `${this.getDirective(br.directiveRecord.directiveIndex)}.${br.propertyName}`;
|
||||
return updateDirectiveTemplate(oldValue, newValue, directiveProperty);
|
||||
} else {
|
||||
return updateElementTemplate(oldValue, newValue);
|
||||
@ -513,7 +521,7 @@ export class ChangeDetectorJITGenerator {
|
||||
genNotifyOnChanges(r:ProtoRecord):string{
|
||||
var br = r.bindingRecord;
|
||||
if (r.lastInDirective && br.callOnChange()) {
|
||||
return notifyOnChangesTemplate(this.getDirective(br.directiveRecord));
|
||||
return notifyOnChangesTemplate(this.getDirective(br.directiveRecord.directiveIndex));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
@ -522,7 +530,7 @@ export class ChangeDetectorJITGenerator {
|
||||
genNotifyOnPushDetectors(r:ProtoRecord):string{
|
||||
var br = r.bindingRecord;
|
||||
if (r.lastInDirective && br.isOnPushChangeDetection()) {
|
||||
return notifyOnPushDetectorsTemplate(this.getDetector(br.directiveRecord));
|
||||
return notifyOnPushDetectorsTemplate(this.getDetector(br.directiveRecord.directiveIndex));
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ function _selfRecord(r:ProtoRecord, contextIndex:number, selfIndex:number):Proto
|
||||
[],
|
||||
r.fixedArgs,
|
||||
contextIndex,
|
||||
r.directiveIndex,
|
||||
selfIndex,
|
||||
r.bindingRecord,
|
||||
r.expressionAsString,
|
||||
@ -72,6 +73,7 @@ function _replaceIndices(r:ProtoRecord, selfIndex:number, indexMap:Map) {
|
||||
args,
|
||||
r.fixedArgs,
|
||||
contextIndex,
|
||||
r.directiveIndex,
|
||||
selfIndex,
|
||||
r.bindingRecord,
|
||||
r.expressionAsString,
|
||||
|
@ -1,16 +1,27 @@
|
||||
import {ON_PUSH} from './constants';
|
||||
import {StringWrapper} from 'angular2/src/facade/lang';
|
||||
|
||||
export class DirectiveRecord {
|
||||
export class DirectiveIndex {
|
||||
elementIndex:number;
|
||||
directiveIndex:number;
|
||||
|
||||
constructor(elementIndex:number, directiveIndex:number) {
|
||||
this.elementIndex = elementIndex;
|
||||
this.directiveIndex = directiveIndex;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return `${this.elementIndex}_${this.directiveIndex}`;
|
||||
}
|
||||
}
|
||||
|
||||
export class DirectiveRecord {
|
||||
directiveIndex:DirectiveIndex;
|
||||
callOnAllChangesDone:boolean;
|
||||
callOnChange:boolean;
|
||||
changeDetection:string;
|
||||
|
||||
constructor(elementIndex:number, directiveIndex:number,
|
||||
callOnAllChangesDone:boolean, callOnChange:boolean, changeDetection:string) {
|
||||
this.elementIndex = elementIndex;
|
||||
constructor(directiveIndex:DirectiveIndex, callOnAllChangesDone:boolean, callOnChange:boolean, changeDetection:string) {
|
||||
this.directiveIndex = directiveIndex;
|
||||
this.callOnAllChangesDone = callOnAllChangesDone;
|
||||
this.callOnChange = callOnChange;
|
||||
@ -20,8 +31,4 @@ export class DirectiveRecord {
|
||||
isOnPushChangeDetection():boolean {
|
||||
return StringWrapper.equals(this.changeDetection, ON_PUSH);
|
||||
}
|
||||
|
||||
get name() {
|
||||
return `${this.elementIndex}_${this.directiveIndex}`;
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ import {List, ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/faca
|
||||
|
||||
import {AbstractChangeDetector} from './abstract_change_detector';
|
||||
import {BindingRecord} from './binding_record';
|
||||
import {DirectiveRecord} from './directive_record';
|
||||
import {PipeRegistry} from './pipes/pipe_registry';
|
||||
import {ChangeDetectionUtil, uninitialized} from './change_detection_util';
|
||||
|
||||
@ -111,12 +110,12 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
|
||||
if (proto.lastInDirective) {
|
||||
if (isPresent(changes)) {
|
||||
this._getDirectiveFor(directiveRecord).onChange(changes);
|
||||
this._getDirectiveFor(directiveRecord.directiveIndex).onChange(changes);
|
||||
changes = null;
|
||||
}
|
||||
|
||||
if (isChanged && bindingRecord.isOnPushChangeDetection()) {
|
||||
this._getDetectorFor(directiveRecord).markAsCheckOnce();
|
||||
this._getDetectorFor(directiveRecord.directiveIndex).markAsCheckOnce();
|
||||
}
|
||||
|
||||
isChanged = false;
|
||||
@ -129,7 +128,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
for (var i = dirs.length - 1; i >= 0; --i) {
|
||||
var dir = dirs[i];
|
||||
if (dir.callOnAllChangesDone) {
|
||||
this._getDirectiveFor(dir).onAllChangesDone();
|
||||
this._getDirectiveFor(dir.directiveIndex).onAllChangesDone();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -138,7 +137,8 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
if (isBlank(bindingRecord.directiveRecord)) {
|
||||
this.dispatcher.notifyOnBinding(bindingRecord, change.currentValue);
|
||||
} else {
|
||||
bindingRecord.setter(this._getDirectiveFor(bindingRecord.directiveRecord), change.currentValue);
|
||||
var directiveIndex = bindingRecord.directiveRecord.directiveIndex;
|
||||
bindingRecord.setter(this._getDirectiveFor(directiveIndex), change.currentValue);
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,12 +150,12 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
}
|
||||
}
|
||||
|
||||
_getDirectiveFor(directive:DirectiveRecord) {
|
||||
return this.directives.getDirectiveFor(directive);
|
||||
_getDirectiveFor(directiveIndex) {
|
||||
return this.directives.getDirectiveFor(directiveIndex);
|
||||
}
|
||||
|
||||
_getDetectorFor(directive:DirectiveRecord) {
|
||||
return this.directives.getDetectorFor(directive);
|
||||
_getDetectorFor(directiveIndex) {
|
||||
return this.directives.getDetectorFor(directiveIndex);
|
||||
}
|
||||
|
||||
_check(proto:ProtoRecord) {
|
||||
@ -235,6 +235,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
var pipe = this._pipeFor(proto, context);
|
||||
|
||||
var newValue = pipe.transform(context);
|
||||
|
||||
if (! ChangeDetectionUtil.noChangeMarker(newValue)) {
|
||||
var prevValue = this._readSelf(proto);
|
||||
this._writeSelf(proto, newValue);
|
||||
@ -272,6 +273,12 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
}
|
||||
|
||||
_readContext(proto:ProtoRecord) {
|
||||
if (proto.contextIndex == -1) {
|
||||
return this._getDirectiveFor(proto.directiveIndex);
|
||||
} else {
|
||||
return this.values[proto.contextIndex];
|
||||
}
|
||||
|
||||
return this.values[proto.contextIndex];
|
||||
}
|
||||
|
||||
|
@ -450,7 +450,7 @@ export class AstVisitor {
|
||||
|
||||
export class AstTransformer {
|
||||
visitImplicitReceiver(ast:ImplicitReceiver) {
|
||||
return new ImplicitReceiver();
|
||||
return ast;
|
||||
}
|
||||
|
||||
visitInterpolation(ast:Interpolation) {
|
||||
|
@ -28,6 +28,7 @@ import {DynamicChangeDetector} from './dynamic_change_detector';
|
||||
import {ChangeDetectorJITGenerator} from './change_detection_jit_generator';
|
||||
import {PipeRegistry} from './pipes/pipe_registry';
|
||||
import {BindingRecord} from './binding_record';
|
||||
import {DirectiveIndex} from './directive_record';
|
||||
|
||||
import {coalesce} from './coalesce';
|
||||
|
||||
@ -153,7 +154,7 @@ class _ConvertAstIntoProtoRecords {
|
||||
}
|
||||
|
||||
visitImplicitReceiver(ast:ImplicitReceiver) {
|
||||
return 0;
|
||||
return this.bindingRecord.implicitReceiver;
|
||||
}
|
||||
|
||||
visitInterpolation(ast:Interpolation) {
|
||||
@ -247,9 +248,15 @@ class _ConvertAstIntoProtoRecords {
|
||||
|
||||
_addRecord(type, name, funcOrValue, args, fixedArgs, context) {
|
||||
var selfIndex = ++ this.contextIndex;
|
||||
ListWrapper.push(this.protoRecords,
|
||||
new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, selfIndex,
|
||||
this.bindingRecord, this.expressionAsString, false, false));
|
||||
if (context instanceof DirectiveIndex) {
|
||||
ListWrapper.push(this.protoRecords,
|
||||
new ProtoRecord(type, name, funcOrValue, args, fixedArgs, -1, context, selfIndex,
|
||||
this.bindingRecord, this.expressionAsString, false, false));
|
||||
} else {
|
||||
ListWrapper.push(this.protoRecords,
|
||||
new ProtoRecord(type, name, funcOrValue, args, fixedArgs, context, null, selfIndex,
|
||||
this.bindingRecord, this.expressionAsString, false, false));
|
||||
}
|
||||
return selfIndex;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {List} from 'angular2/src/facade/collection';
|
||||
import {BindingRecord} from './binding_record';
|
||||
import {DirectiveIndex} from './directive_record';
|
||||
|
||||
export const RECORD_TYPE_SELF = 0;
|
||||
export const RECORD_TYPE_CONST = 1;
|
||||
@ -19,7 +20,10 @@ export class ProtoRecord {
|
||||
funcOrValue:any;
|
||||
args:List;
|
||||
fixedArgs:List;
|
||||
|
||||
contextIndex:number;
|
||||
directiveIndex:DirectiveIndex;
|
||||
|
||||
selfIndex:number;
|
||||
bindingRecord:BindingRecord;
|
||||
lastInBinding:boolean;
|
||||
@ -32,6 +36,7 @@ export class ProtoRecord {
|
||||
args:List,
|
||||
fixedArgs:List,
|
||||
contextIndex:number,
|
||||
directiveIndex:DirectiveIndex,
|
||||
selfIndex:number,
|
||||
bindingRecord:BindingRecord,
|
||||
expressionAsString:string,
|
||||
@ -43,7 +48,10 @@ export class ProtoRecord {
|
||||
this.funcOrValue = funcOrValue;
|
||||
this.args = args;
|
||||
this.fixedArgs = fixedArgs;
|
||||
|
||||
this.contextIndex = contextIndex;
|
||||
this.directiveIndex = directiveIndex;
|
||||
|
||||
this.selfIndex = selfIndex;
|
||||
this.bindingRecord = bindingRecord;
|
||||
this.lastInBinding = lastInBinding;
|
||||
|
Reference in New Issue
Block a user