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

@ -72,12 +72,14 @@ export class DirectiveBinder {
// that replaced the values that should be extracted from the element
// with a local name
eventBindings: List<EventBinding>;
hostPropertyBindings: Map<string, ASTWithSource>;
constructor({
directiveIndex, propertyBindings, eventBindings
directiveIndex, propertyBindings, eventBindings, hostPropertyBindings
}) {
this.directiveIndex = directiveIndex;
this.propertyBindings = propertyBindings;
this.eventBindings = eventBindings;
this.hostPropertyBindings = hostPropertyBindings;
}
}
@ -114,17 +116,17 @@ export class DirectiveMetadata {
selector:string;
compileChildren:boolean;
hostListeners:Map<string, string>;
hostProperties:Map<string, string>;
properties:Map<string, string>;
setters:List<string>;
readAttributes:List<string>;
type:number;
constructor({id, selector, compileChildren, hostListeners, properties, setters, readAttributes, type}) {
constructor({id, selector, compileChildren, hostListeners, hostProperties, properties, readAttributes, type}) {
this.id = id;
this.selector = selector;
this.compileChildren = isPresent(compileChildren) ? compileChildren : true;
this.hostListeners = hostListeners;
this.hostProperties = hostProperties;
this.properties = properties;
this.setters = setters;
this.readAttributes = readAttributes;
this.type = type;
}
@ -248,7 +250,7 @@ export class Renderer {
/**
* Sets a property on an element.
* Note: This will fail if the property was not mentioned previously as a propertySetter
* Note: This will fail if the property was not mentioned previously as a host property
* in the View.
*/
setElementProperty(view:ViewRef, elementIndex:number, propertyName:string, propertyValue:any):void {}

View File

@ -56,21 +56,21 @@ export class DirectiveParser extends CompileStep {
this._selectorMatcher.match(cssSelector, (selector, directiveIndex) => {
var elementBinder = current.bindElement();
var directive = this._directives[directiveIndex];
var directiveBinder = elementBinder.bindDirective(directiveIndex);
var directiveBinderBuilder = elementBinder.bindDirective(directiveIndex);
current.compileChildren = current.compileChildren && directive.compileChildren;
if (isPresent(directive.properties)) {
MapWrapper.forEach(directive.properties, (bindConfig, dirProperty) => {
this._bindDirectiveProperty(dirProperty, bindConfig, current, directiveBinder);
this._bindDirectiveProperty(dirProperty, bindConfig, current, directiveBinderBuilder);
});
}
if (isPresent(directive.hostListeners)) {
MapWrapper.forEach(directive.hostListeners, (action, eventName) => {
this._bindDirectiveEvent(eventName, action, current, directiveBinder);
this._bindDirectiveEvent(eventName, action, current, directiveBinderBuilder);
});
}
if (isPresent(directive.setters)) {
ListWrapper.forEach(directive.setters, (propertyName) => {
elementBinder.bindPropertySetter(propertyName);
if (isPresent(directive.hostProperties)) {
MapWrapper.forEach(directive.hostProperties, (hostPropertyName, directivePropertyName) => {
this._bindHostProperty(hostPropertyName, directivePropertyName, current, directiveBinderBuilder);
});
}
if (isPresent(directive.readAttributes)) {
@ -102,7 +102,7 @@ export class DirectiveParser extends CompileStep {
});
}
_bindDirectiveProperty(dirProperty, bindConfig, compileElement, directiveBinder) {
_bindDirectiveProperty(dirProperty, bindConfig, compileElement, directiveBinderBuilder) {
var pipes = this._splitBindConfig(bindConfig);
var elProp = ListWrapper.removeAt(pipes, 0);
@ -124,21 +124,27 @@ export class DirectiveParser extends CompileStep {
// Bindings are optional, so this binding only needs to be set up if an expression is given.
if (isPresent(bindingAst)) {
var fullExpAstWithBindPipes = this._parser.addPipes(bindingAst, pipes);
directiveBinder.bindProperty(
directiveBinderBuilder.bindProperty(
dirProperty, fullExpAstWithBindPipes
);
}
}
_bindDirectiveEvent(eventName, action, compileElement, directiveBinder) {
_bindDirectiveEvent(eventName, action, compileElement, directiveBinderBuilder) {
var ast = this._parser.parseAction(action, compileElement.elementDescription);
if (StringWrapper.contains(eventName, EVENT_TARGET_SEPARATOR)) {
var parts = eventName.split(EVENT_TARGET_SEPARATOR);
directiveBinder.bindEvent(parts[1], ast, parts[0]);
directiveBinderBuilder.bindEvent(parts[1], ast, parts[0]);
} else {
directiveBinder.bindEvent(eventName, ast);
directiveBinderBuilder.bindEvent(eventName, ast);
}
}
_bindHostProperty(hostPropertyName, directivePropertyName, compileElement, directiveBinderBuilder) {
var ast = this._parser.parseBinding(directivePropertyName,
`hostProperties of ${compileElement.elementDescription}`);
directiveBinderBuilder.bindHostProperty(hostPropertyName, ast);
}
_splitBindConfig(bindConfig:string) {

View File

@ -5,7 +5,6 @@ import {DOM} from 'angular2/src/dom/dom_adapter';
import {
ASTWithSource, AST, AstTransformer, AccessMember, LiteralArray, ImplicitReceiver
} from 'angular2/change_detection';
import {SetterFn} from 'angular2/src/reflection/types';
import {RenderProtoView} from './proto_view';
import {ElementBinder, Event} from './element_binder';
@ -57,17 +56,26 @@ export class ProtoViewBuilder {
var apiElementBinders = [];
ListWrapper.forEach(this.elements, (ebb) => {
var propertySetters = MapWrapper.create();
var apiDirectiveBinders = ListWrapper.map(ebb.directives, (db) => {
ebb.eventBuilder.merge(db.eventBuilder);
var apiDirectiveBinders = ListWrapper.map(ebb.directives, (dbb) => {
ebb.eventBuilder.merge(dbb.eventBuilder);
MapWrapper.forEach(dbb.hostPropertyBindings, (_, hostPropertyName) => {
MapWrapper.set(propertySetters, hostPropertyName, setterFactory(hostPropertyName));
});
return new api.DirectiveBinder({
directiveIndex: db.directiveIndex,
propertyBindings: db.propertyBindings,
eventBindings: db.eventBindings
directiveIndex: dbb.directiveIndex,
propertyBindings: dbb.propertyBindings,
eventBindings: dbb.eventBindings,
hostPropertyBindings: dbb.hostPropertyBindings
});
});
MapWrapper.forEach(ebb.propertySetters, (setter, propertyName) => {
MapWrapper.set(propertySetters, propertyName, setter);
MapWrapper.forEach(ebb.propertyBindings, (_, propertyName) => {
MapWrapper.set(propertySetters, propertyName, setterFactory(propertyName));
});
var nestedProtoView =
isPresent(ebb.nestedProtoView) ? ebb.nestedProtoView.build() : null;
var parentIndex = isPresent(ebb.parent) ? ebb.parent.index : -1;
@ -119,7 +127,6 @@ export class ElementBinderBuilder {
textBindingIndices: List<number>;
textBindings: List<ASTWithSource>;
contentTagSelector:string;
propertySetters: Map<string, SetterFn>;
readAttributes: Map<string, string>;
componentId: string;
@ -137,7 +144,6 @@ export class ElementBinderBuilder {
this.textBindings = [];
this.textBindingIndices = [];
this.contentTagSelector = null;
this.propertySetters = MapWrapper.create();
this.componentId = null;
this.readAttributes = MapWrapper.create();
}
@ -172,11 +178,10 @@ export class ElementBinderBuilder {
bindProperty(name, expression) {
MapWrapper.set(this.propertyBindings, name, expression);
this.bindPropertySetter(name);
}
bindPropertySetter(name) {
MapWrapper.set(this.propertySetters, name, setterFactory(name));
//TODO: required for Dart transformers. Remove when Dart transformers
//run all the steps of the render compiler
setterFactory(name);
}
bindVariable(name, value) {
@ -216,12 +221,14 @@ export class ElementBinderBuilder {
export class DirectiveBuilder {
directiveIndex:number;
propertyBindings: Map<string, ASTWithSource>;
hostPropertyBindings: Map<string, ASTWithSource>;
eventBindings: List<api.EventBinding>;
eventBuilder: EventBuilder;
constructor(directiveIndex) {
this.directiveIndex = directiveIndex;
this.propertyBindings = MapWrapper.create();
this.hostPropertyBindings = MapWrapper.create();
this.eventBindings = ListWrapper.create();
this.eventBuilder = new EventBuilder();
}
@ -230,6 +237,10 @@ export class DirectiveBuilder {
MapWrapper.set(this.propertyBindings, name, expression);
}
bindHostProperty(name, expression) {
MapWrapper.set(this.hostPropertyBindings, name, expression);
}
bindEvent(name, expression, target = null) {
ListWrapper.push(this.eventBindings, this.eventBuilder.add(name, expression, target));
}