refactor(ElementBinder): Store componentDirective and templateDirective as well.
This commit is contained in:
parent
352b6406ad
commit
5e0ff2cbb7
|
@ -17,7 +17,7 @@ export class Component extends Directive {
|
||||||
template:TemplateConfig,
|
template:TemplateConfig,
|
||||||
lightDomServices:DomServicesFunction,
|
lightDomServices:DomServicesFunction,
|
||||||
shadowDomServices:DomServicesFunction,
|
shadowDomServices:DomServicesFunction,
|
||||||
componentServices:ComponentServicesFunction,
|
componentServices:Array,
|
||||||
implementsTypes:Array<Type>
|
implementsTypes:Array<Type>
|
||||||
}={})
|
}={})
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,16 +1,20 @@
|
||||||
import {ProtoElementInjector} from './element_injector';
|
import {ProtoElementInjector} from './element_injector';
|
||||||
import {FIELD} from 'facade/lang';
|
import {FIELD} from 'facade/lang';
|
||||||
|
import {AnnotatedType} from './annotated_type';
|
||||||
// Comment out as dartanalyzer does not look into @FIELD
|
// Comment out as dartanalyzer does not look into @FIELD
|
||||||
// import {List} from 'facade/collection';
|
// import {List} from 'facade/collection';
|
||||||
// import {ProtoView} from './view';
|
// import {ProtoView} from './view';
|
||||||
|
|
||||||
export class ElementBinder {
|
export class ElementBinder {
|
||||||
@FIELD('final protoElementInjector:ProtoElementInjector')
|
@FIELD('final protoElementInjector:ProtoElementInjector')
|
||||||
|
@FIELD('final componentDirective:AnnotatedType')
|
||||||
|
@FIELD('final templateDirective:AnnotatedType')
|
||||||
@FIELD('final textNodeIndices:List<int>')
|
@FIELD('final textNodeIndices:List<int>')
|
||||||
@FIELD('hasElementPropertyBindings:bool')
|
@FIELD('hasElementPropertyBindings:bool')
|
||||||
@FIELD('nestedProtoView:ProtoView')
|
constructor(protoElementInjector: ProtoElementInjector, componentDirective:AnnotatedType, templateDirective:AnnotatedType) {
|
||||||
constructor(protoElementInjector: ProtoElementInjector) {
|
|
||||||
this.protoElementInjector = protoElementInjector;
|
this.protoElementInjector = protoElementInjector;
|
||||||
|
this.componentDirective = componentDirective;
|
||||||
|
this.templateDirective = templateDirective;
|
||||||
// updated later when text nodes are bound
|
// updated later when text nodes are bound
|
||||||
this.textNodeIndices = [];
|
this.textNodeIndices = [];
|
||||||
// updated later when element properties are bound
|
// updated later when element properties are bound
|
||||||
|
|
|
@ -52,7 +52,8 @@ export class ElementBinderBuilder extends CompileStep {
|
||||||
var elementBinder;
|
var elementBinder;
|
||||||
if (current.hasBindings) {
|
if (current.hasBindings) {
|
||||||
var protoView = current.inheritedProtoView;
|
var protoView = current.inheritedProtoView;
|
||||||
elementBinder = protoView.bindElement(current.inheritedProtoElementInjector);
|
elementBinder = protoView.bindElement(current.inheritedProtoElementInjector,
|
||||||
|
current.componentDirective, current.templateDirective);
|
||||||
|
|
||||||
if (isPresent(current.textNodeBindings)) {
|
if (isPresent(current.textNodeBindings)) {
|
||||||
this._bindTextNodes(protoView, current.textNodeBindings);
|
this._bindTextNodes(protoView, current.textNodeBindings);
|
||||||
|
|
|
@ -3,8 +3,10 @@ import {ListWrapper} from 'facade/collection';
|
||||||
import {ProtoWatchGroup, WatchGroup, WatchGroupDispatcher} from 'change_detection/watch_group';
|
import {ProtoWatchGroup, WatchGroup, WatchGroupDispatcher} from 'change_detection/watch_group';
|
||||||
import {Record} from 'change_detection/record';
|
import {Record} from 'change_detection/record';
|
||||||
import {AST} from 'change_detection/parser/ast';
|
import {AST} from 'change_detection/parser/ast';
|
||||||
|
|
||||||
import {ProtoElementInjector, ElementInjector} from './element_injector';
|
import {ProtoElementInjector, ElementInjector} from './element_injector';
|
||||||
import {ElementBinder} from './element_binder';
|
import {ElementBinder} from './element_binder';
|
||||||
|
import {AnnotatedType} from './annotated_type';
|
||||||
import {SetterFn} from 'change_detection/parser/closure_map';
|
import {SetterFn} from 'change_detection/parser/closure_map';
|
||||||
import {FIELD, IMPLEMENTS, int, isPresent, isBlank} from 'facade/lang';
|
import {FIELD, IMPLEMENTS, int, isPresent, isBlank} from 'facade/lang';
|
||||||
import {List} from 'facade/collection';
|
import {List} from 'facade/collection';
|
||||||
|
@ -99,8 +101,9 @@ export class ProtoView {
|
||||||
bindElements, this.protoWatchGroup, context);
|
bindElements, this.protoWatchGroup, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
bindElement(protoElementInjector:ProtoElementInjector):ElementBinder {
|
bindElement(protoElementInjector:ProtoElementInjector,
|
||||||
var elBinder = new ElementBinder(protoElementInjector);
|
componentDirective:AnnotatedType = null, templateDirective:AnnotatedType = null):ElementBinder {
|
||||||
|
var elBinder = new ElementBinder(protoElementInjector, componentDirective, templateDirective);
|
||||||
ListWrapper.push(this.elementBinders, elBinder);
|
ListWrapper.push(this.elementBinders, elBinder);
|
||||||
return elBinder;
|
return elBinder;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ export function main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store the current protoElementInjector', () => {
|
it('should store the current protoElementInjector', () => {
|
||||||
var directives = [SomeSimpleDirective];
|
var directives = [SomeDecoratorDirective];
|
||||||
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
|
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
|
||||||
|
|
||||||
var pipeline = createPipeline({protoElementInjector: protoElementInjector, directives: directives});
|
var pipeline = createPipeline({protoElementInjector: protoElementInjector, directives: directives});
|
||||||
|
@ -110,6 +110,24 @@ export function main() {
|
||||||
expect(pv.elementBinders[0].protoElementInjector).toBe(protoElementInjector);
|
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', () => {
|
it('should bind text nodes', () => {
|
||||||
var textNodeBindings = MapWrapper.create();
|
var textNodeBindings = MapWrapper.create();
|
||||||
MapWrapper.set(textNodeBindings, 0, 'prop1');
|
MapWrapper.set(textNodeBindings, 0, 'prop1');
|
||||||
|
@ -155,7 +173,7 @@ export function main() {
|
||||||
'boundprop2': 'prop2',
|
'boundprop2': 'prop2',
|
||||||
'boundprop3': 'prop3'
|
'boundprop3': 'prop3'
|
||||||
});
|
});
|
||||||
var directives = [SomeDecoratorDirective, SomeTemplateDirective, SomeComponentDirective];
|
var directives = [SomeDecoratorDirectiveWithBinding, SomeTemplateDirectiveWithBinding, SomeComponentDirectiveWithBinding];
|
||||||
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
|
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
|
||||||
var pipeline = createPipeline({
|
var pipeline = createPipeline({
|
||||||
propertyBindings: propertyBindings,
|
propertyBindings: propertyBindings,
|
||||||
|
@ -171,16 +189,16 @@ export function main() {
|
||||||
evalContext.prop3 = 'c';
|
evalContext.prop3 = 'c';
|
||||||
changeDetector.detectChanges();
|
changeDetector.detectChanges();
|
||||||
|
|
||||||
expect(view.elementInjectors[0].get(SomeDecoratorDirective).decorProp).toBe('a');
|
expect(view.elementInjectors[0].get(SomeDecoratorDirectiveWithBinding).decorProp).toBe('a');
|
||||||
expect(view.elementInjectors[0].get(SomeTemplateDirective).templProp).toBe('b');
|
expect(view.elementInjectors[0].get(SomeTemplateDirectiveWithBinding).templProp).toBe('b');
|
||||||
expect(view.elementInjectors[0].get(SomeComponentDirective).compProp).toBe('c');
|
expect(view.elementInjectors[0].get(SomeComponentDirectiveWithBinding).compProp).toBe('c');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should bind directive properties for sibling elements', () => {
|
it('should bind directive properties for sibling elements', () => {
|
||||||
var propertyBindings = MapWrapper.createFromStringMap({
|
var propertyBindings = MapWrapper.createFromStringMap({
|
||||||
'boundprop1': 'prop1'
|
'boundprop1': 'prop1'
|
||||||
});
|
});
|
||||||
var directives = [SomeDecoratorDirective];
|
var directives = [SomeDecoratorDirectiveWithBinding];
|
||||||
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
|
var protoElementInjector = new ProtoElementInjector(null, 0, directives);
|
||||||
var pipeline = createPipeline({
|
var pipeline = createPipeline({
|
||||||
propertyBindings: propertyBindings,
|
propertyBindings: propertyBindings,
|
||||||
|
@ -196,16 +214,16 @@ export function main() {
|
||||||
evalContext.prop1 = 'a';
|
evalContext.prop1 = 'a';
|
||||||
changeDetector.detectChanges();
|
changeDetector.detectChanges();
|
||||||
|
|
||||||
expect(view.elementInjectors[1].get(SomeDecoratorDirective).decorProp).toBe('a');
|
expect(view.elementInjectors[1].get(SomeDecoratorDirectiveWithBinding).decorProp).toBe('a');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('errors', () => {
|
describe('errors', () => {
|
||||||
|
|
||||||
it('should throw if there is no element property bindings for a directive property binding', () => {
|
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( () => {
|
expect( () => {
|
||||||
pipeline.process(createElement('<div viewroot prop-binding directives>'));
|
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()
|
@Decorator()
|
||||||
class SomeSimpleDirective {
|
class SomeDecoratorDirective {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Decorator({
|
@Decorator({
|
||||||
bind: {'boundprop1': 'decorProp'}
|
bind: {'boundprop1': 'decorProp'}
|
||||||
})
|
})
|
||||||
class SomeDecoratorDirective {
|
class SomeDecoratorDirectiveWithBinding {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.decorProp = null;
|
this.decorProp = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Template()
|
||||||
|
class SomeTemplateDirective {
|
||||||
|
}
|
||||||
|
|
||||||
@Template({
|
@Template({
|
||||||
bind: {'boundprop2': 'templProp'}
|
bind: {'boundprop2': 'templProp'}
|
||||||
})
|
})
|
||||||
class SomeTemplateDirective {
|
class SomeTemplateDirectiveWithBinding {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.templProp = null;
|
this.templProp = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Component()
|
||||||
|
class SomeComponentDirective {
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
bind: {'boundprop3': 'compProp'}
|
bind: {'boundprop3': 'compProp'}
|
||||||
})
|
})
|
||||||
class SomeComponentDirective {
|
class SomeComponentDirectiveWithBinding {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.compProp = null;
|
this.compProp = null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ export function main() {
|
||||||
if (isPresent(current.element.getAttribute('viewroot'))) {
|
if (isPresent(current.element.getAttribute('viewroot'))) {
|
||||||
current.isViewRoot = true;
|
current.isViewRoot = true;
|
||||||
}
|
}
|
||||||
current.inheritedElementBinder = new ElementBinder(null);
|
current.inheritedElementBinder = new ElementBinder(null, null, null);
|
||||||
}), new ProtoViewBuilder()]);
|
}), new ProtoViewBuilder()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue