feat(view): reimplemented property setters using change detection

This commit is contained in:
vsavkin
2015-04-21 11:47:53 -07:00
parent 8a92a1f13e
commit 8ccafb0524
36 changed files with 510 additions and 469 deletions

View File

@ -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);
}
}

View File

@ -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 "";
}

View File

@ -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,

View File

@ -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}`;
}
}

View File

@ -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];
}

View File

@ -450,7 +450,7 @@ export class AstVisitor {
export class AstTransformer {
visitImplicitReceiver(ast:ImplicitReceiver) {
return new ImplicitReceiver();
return ast;
}
visitInterpolation(ast:Interpolation) {

View File

@ -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;
}
}

View File

@ -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;