refactor(ElementBinder): Store componentDirective and templateDirective as well.

This commit is contained in:
Tobias Bosch 2014-11-13 15:15:55 -08:00
parent 352b6406ad
commit 5e0ff2cbb7
6 changed files with 54 additions and 20 deletions

View File

@ -17,7 +17,7 @@ export class Component extends Directive {
template:TemplateConfig,
lightDomServices:DomServicesFunction,
shadowDomServices:DomServicesFunction,
componentServices:ComponentServicesFunction,
componentServices:Array,
implementsTypes:Array<Type>
}={})
{

View File

@ -1,16 +1,20 @@
import {ProtoElementInjector} from './element_injector';
import {FIELD} from 'facade/lang';
import {AnnotatedType} from './annotated_type';
// Comment out as dartanalyzer does not look into @FIELD
// import {List} from 'facade/collection';
// import {ProtoView} from './view';
export class ElementBinder {
@FIELD('final protoElementInjector:ProtoElementInjector')
@FIELD('final componentDirective:AnnotatedType')
@FIELD('final templateDirective:AnnotatedType')
@FIELD('final textNodeIndices:List<int>')
@FIELD('hasElementPropertyBindings:bool')
@FIELD('nestedProtoView:ProtoView')
constructor(protoElementInjector: ProtoElementInjector) {
constructor(protoElementInjector: ProtoElementInjector, componentDirective:AnnotatedType, templateDirective:AnnotatedType) {
this.protoElementInjector = protoElementInjector;
this.componentDirective = componentDirective;
this.templateDirective = templateDirective;
// updated later when text nodes are bound
this.textNodeIndices = [];
// updated later when element properties are bound

View File

@ -52,7 +52,8 @@ export class ElementBinderBuilder extends CompileStep {
var elementBinder;
if (current.hasBindings) {
var protoView = current.inheritedProtoView;
elementBinder = protoView.bindElement(current.inheritedProtoElementInjector);
elementBinder = protoView.bindElement(current.inheritedProtoElementInjector,
current.componentDirective, current.templateDirective);
if (isPresent(current.textNodeBindings)) {
this._bindTextNodes(protoView, current.textNodeBindings);

View File

@ -3,8 +3,10 @@ import {ListWrapper} from 'facade/collection';
import {ProtoWatchGroup, WatchGroup, WatchGroupDispatcher} from 'change_detection/watch_group';
import {Record} from 'change_detection/record';
import {AST} from 'change_detection/parser/ast';
import {ProtoElementInjector, ElementInjector} from './element_injector';
import {ElementBinder} from './element_binder';
import {AnnotatedType} from './annotated_type';
import {SetterFn} from 'change_detection/parser/closure_map';
import {FIELD, IMPLEMENTS, int, isPresent, isBlank} from 'facade/lang';
import {List} from 'facade/collection';
@ -99,8 +101,9 @@ export class ProtoView {
bindElements, this.protoWatchGroup, context);
}
bindElement(protoElementInjector:ProtoElementInjector):ElementBinder {
var elBinder = new ElementBinder(protoElementInjector);
bindElement(protoElementInjector:ProtoElementInjector,
componentDirective:AnnotatedType = null, templateDirective:AnnotatedType = null):ElementBinder {
var elBinder = new ElementBinder(protoElementInjector, componentDirective, templateDirective);
ListWrapper.push(this.elementBinders, elBinder);
return elBinder;
}

View File

@ -100,7 +100,7 @@ export function main() {
});
it('should store the current protoElementInjector', () => {
var directives = [SomeSimpleDirective];
var directives = [SomeDecoratorDirective];
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
var pipeline = createPipeline({protoElementInjector: protoElementInjector, directives: directives});
@ -110,6 +110,24 @@ export function main() {
expect(pv.elementBinders[0].protoElementInjector).toBe(protoElementInjector);
});
it('should store the component directive', () => {
var directives = [SomeComponentDirective];
var pipeline = createPipeline({protoElementInjector: null, directives: directives});
var results = pipeline.process(createElement('<div viewroot directives></div>'));
var pv = results[0].inheritedProtoView;
expect(pv.elementBinders[0].componentDirective.type).toBe(SomeComponentDirective);
});
it('should store the template directive', () => {
var directives = [SomeTemplateDirective];
var pipeline = createPipeline({protoElementInjector: null, directives: directives});
var results = pipeline.process(createElement('<div viewroot directives></div>'));
var pv = results[0].inheritedProtoView;
expect(pv.elementBinders[0].templateDirective.type).toBe(SomeTemplateDirective);
});
it('should bind text nodes', () => {
var textNodeBindings = MapWrapper.create();
MapWrapper.set(textNodeBindings, 0, 'prop1');
@ -155,7 +173,7 @@ export function main() {
'boundprop2': 'prop2',
'boundprop3': 'prop3'
});
var directives = [SomeDecoratorDirective, SomeTemplateDirective, SomeComponentDirective];
var directives = [SomeDecoratorDirectiveWithBinding, SomeTemplateDirectiveWithBinding, SomeComponentDirectiveWithBinding];
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
var pipeline = createPipeline({
propertyBindings: propertyBindings,
@ -171,16 +189,16 @@ export function main() {
evalContext.prop3 = 'c';
changeDetector.detectChanges();
expect(view.elementInjectors[0].get(SomeDecoratorDirective).decorProp).toBe('a');
expect(view.elementInjectors[0].get(SomeTemplateDirective).templProp).toBe('b');
expect(view.elementInjectors[0].get(SomeComponentDirective).compProp).toBe('c');
expect(view.elementInjectors[0].get(SomeDecoratorDirectiveWithBinding).decorProp).toBe('a');
expect(view.elementInjectors[0].get(SomeTemplateDirectiveWithBinding).templProp).toBe('b');
expect(view.elementInjectors[0].get(SomeComponentDirectiveWithBinding).compProp).toBe('c');
});
it('should bind directive properties for sibling elements', () => {
var propertyBindings = MapWrapper.createFromStringMap({
'boundprop1': 'prop1'
});
var directives = [SomeDecoratorDirective];
var directives = [SomeDecoratorDirectiveWithBinding];
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
var pipeline = createPipeline({
propertyBindings: propertyBindings,
@ -196,16 +214,16 @@ export function main() {
evalContext.prop1 = 'a';
changeDetector.detectChanges();
expect(view.elementInjectors[1].get(SomeDecoratorDirective).decorProp).toBe('a');
expect(view.elementInjectors[1].get(SomeDecoratorDirectiveWithBinding).decorProp).toBe('a');
});
describe('errors', () => {
it('should throw if there is no element property bindings for a directive property binding', () => {
var pipeline = createPipeline({propertyBindings: MapWrapper.create(), directives: [SomeDecoratorDirective]});
var pipeline = createPipeline({propertyBindings: MapWrapper.create(), directives: [SomeDecoratorDirectiveWithBinding]});
expect( () => {
pipeline.process(createElement('<div viewroot prop-binding directives>'));
}).toThrowError('No element binding found for property boundprop1 which is required by directive SomeDecoratorDirective');
}).toThrowError('No element binding found for property boundprop1 which is required by directive SomeDecoratorDirectiveWithBinding');
});
});
@ -215,31 +233,39 @@ export function main() {
}
@Decorator()
class SomeSimpleDirective {
class SomeDecoratorDirective {
}
@Decorator({
bind: {'boundprop1': 'decorProp'}
})
class SomeDecoratorDirective {
class SomeDecoratorDirectiveWithBinding {
constructor() {
this.decorProp = null;
}
}
@Template()
class SomeTemplateDirective {
}
@Template({
bind: {'boundprop2': 'templProp'}
})
class SomeTemplateDirective {
class SomeTemplateDirectiveWithBinding {
constructor() {
this.templProp = null;
}
}
@Component()
class SomeComponentDirective {
}
@Component({
bind: {'boundprop3': 'compProp'}
})
class SomeComponentDirective {
class SomeComponentDirectiveWithBinding {
constructor() {
this.compProp = null;
}

View File

@ -15,7 +15,7 @@ export function main() {
if (isPresent(current.element.getAttribute('viewroot'))) {
current.isViewRoot = true;
}
current.inheritedElementBinder = new ElementBinder(null);
current.inheritedElementBinder = new ElementBinder(null, null, null);
}), new ProtoViewBuilder()]);
}