feat(view): reimplemented property setters using change detection
This commit is contained in:
@ -22,7 +22,7 @@ import {AppProtoView} from 'angular2/src/core/compiler/view';
|
||||
import {ElementBinder} from 'angular2/src/core/compiler/element_binder';
|
||||
import {DirectiveMetadataReader} from 'angular2/src/core/compiler/directive_metadata_reader';
|
||||
import {Component, DynamicComponent, Viewport, Decorator} from 'angular2/src/core/annotations/annotations';
|
||||
import {PropertySetter, Attribute} from 'angular2/src/core/annotations/di';
|
||||
import {Attribute} from 'angular2/src/core/annotations/di';
|
||||
import {View} from 'angular2/src/core/annotations/view';
|
||||
import {DirectiveBinding} from 'angular2/src/core/compiler/element_injector';
|
||||
import {TemplateResolver} from 'angular2/src/core/compiler/template_resolver';
|
||||
@ -185,18 +185,20 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should set directive.bind', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(DirectiveWithBind).then( (renderDir) => {
|
||||
expect(renderDir.properties).toEqual(MapWrapper.createFromStringMap({
|
||||
'a': 'b'
|
||||
it('should set directive.hostProperties', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(DirectiveWithProperties).then( (renderDir) => {
|
||||
expect(renderDir.hostProperties).toEqual(MapWrapper.createFromStringMap({
|
||||
'someField': 'someProp'
|
||||
}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
it('should read @PropertySetter', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(DirectiveWithPropertySetters).then( (renderDir) => {
|
||||
expect(renderDir.setters).toEqual(['someProp']);
|
||||
it('should set directive.bind', inject([AsyncTestCompleter], (async) => {
|
||||
captureDirective(DirectiveWithBind).then( (renderDir) => {
|
||||
expect(renderDir.properties).toEqual(MapWrapper.createFromStringMap({
|
||||
'a': 'b'
|
||||
}));
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
@ -500,16 +502,16 @@ class IgnoreChildrenDecoratorDirective {}
|
||||
})
|
||||
class DirectiveWithEvents {}
|
||||
|
||||
@Decorator({
|
||||
hostProperties: {'someField': 'someProp'}
|
||||
})
|
||||
class DirectiveWithProperties {}
|
||||
|
||||
@Decorator({
|
||||
properties: {'a': 'b'}
|
||||
})
|
||||
class DirectiveWithBind {}
|
||||
|
||||
@Decorator()
|
||||
class DirectiveWithPropertySetters {
|
||||
constructor(@PropertySetter('someProp') someProp) {}
|
||||
}
|
||||
|
||||
@Decorator()
|
||||
class DirectiveWithAttributes {
|
||||
constructor(@Attribute('someAttr') someAttr:string) {}
|
||||
@ -568,7 +570,8 @@ class FakeProtoViewFactory extends ProtoViewFactory {
|
||||
this._results = results;
|
||||
}
|
||||
|
||||
createProtoView(componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoViewDto, directives:List<DirectiveBinding>):AppProtoView {
|
||||
createProtoView(componentBinding:DirectiveBinding, renderProtoView: renderApi.ProtoViewDto,
|
||||
directives:List<DirectiveBinding>):AppProtoView {
|
||||
ListWrapper.push(this.requests, [componentBinding, renderProtoView, directives]);
|
||||
return ListWrapper.removeAt(this._results, 0);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import {ListWrapper, MapWrapper, List, StringMapWrapper, iterateListLike} from '
|
||||
import {ProtoElementInjector, PreBuiltObjects, DirectiveBinding, TreeNode, ElementRef}
|
||||
from 'angular2/src/core/compiler/element_injector';
|
||||
import {Parent, Ancestor} from 'angular2/src/core/annotations/visibility';
|
||||
import {PropertySetter, Attribute, Query} from 'angular2/src/core/annotations/di';
|
||||
import {Attribute, Query} from 'angular2/src/core/annotations/di';
|
||||
import {onDestroy} from 'angular2/src/core/annotations/annotations';
|
||||
import {Optional, Injector, Inject, bind} from 'angular2/di';
|
||||
import {AppProtoView, AppView} from 'angular2/src/core/compiler/view';
|
||||
@ -87,51 +87,6 @@ class HasEventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
class NeedsPropertySetter {
|
||||
propSetter;
|
||||
roleSetter;
|
||||
classSetter;
|
||||
classWithDashSetter;
|
||||
styleSetter;
|
||||
unitSetter;
|
||||
constructor(@PropertySetter('title') propSetter: Function, @PropertySetter('attr.role') roleSetter: Function,
|
||||
@PropertySetter('class.active') classSetter: Function, @PropertySetter('class.foo-bar') classWithDashSetter: Function,
|
||||
@PropertySetter('style.width') styleSetter: Function, @PropertySetter('style.height.px') unitSetter: Function) {
|
||||
this.propSetter = propSetter;
|
||||
this.roleSetter = roleSetter;
|
||||
this.classSetter = classSetter;
|
||||
this.classWithDashSetter = classWithDashSetter;
|
||||
this.styleSetter = styleSetter;
|
||||
this.unitSetter = unitSetter;
|
||||
}
|
||||
setProp(value) {
|
||||
this.propSetter(value);
|
||||
}
|
||||
setRole(value) {
|
||||
this.roleSetter(value);
|
||||
}
|
||||
setClass(value) {
|
||||
this.classSetter(value);
|
||||
}
|
||||
setStyle(value) {
|
||||
this.styleSetter(value);
|
||||
}
|
||||
setStyleWithUnit(value) {
|
||||
this.unitSetter(value);
|
||||
}
|
||||
}
|
||||
|
||||
class NeedsPropertySetterNoType {
|
||||
propSetter;
|
||||
constructor(@PropertySetter('title') propSetter) {
|
||||
this.propSetter = propSetter;
|
||||
}
|
||||
|
||||
setProp(value) {
|
||||
this.propSetter(value);
|
||||
}
|
||||
}
|
||||
|
||||
class NeedsAttribute {
|
||||
typeAttribute;
|
||||
titleAttribute;
|
||||
@ -708,45 +663,6 @@ export function main() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('property setter', () => {
|
||||
var renderer, view;
|
||||
|
||||
beforeEach( () => {
|
||||
renderer = new FakeRenderer();
|
||||
var protoView = new AppProtoView(null, null);
|
||||
view = new AppView(renderer, null, protoView, MapWrapper.create());
|
||||
view.render = new ViewRef();
|
||||
});
|
||||
|
||||
it('should be injectable and callable', () => {
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null);
|
||||
var inj = injector([NeedsPropertySetter], null, null, preBuildObject);
|
||||
var component = inj.get(NeedsPropertySetter);
|
||||
component.setProp('foobar');
|
||||
component.setRole('button');
|
||||
component.setClass(true);
|
||||
component.classWithDashSetter(true);
|
||||
component.setStyle('40px');
|
||||
component.setStyleWithUnit(50);
|
||||
|
||||
expect(renderer.log[0]).toEqual([view.render, 0, 'title', 'foobar']);
|
||||
expect(renderer.log[1]).toEqual([view.render, 0, 'attr.role', 'button']);
|
||||
expect(renderer.log[2]).toEqual([view.render, 0, 'class.active', true]);
|
||||
expect(renderer.log[3]).toEqual([view.render, 0, 'class.foo-bar', true]);
|
||||
expect(renderer.log[4]).toEqual([view.render, 0, 'style.width', '40px']);
|
||||
expect(renderer.log[5]).toEqual([view.render, 0, 'style.height.px', 50]);
|
||||
});
|
||||
|
||||
it('should be injectable and callable without specifying param type annotation', () => {
|
||||
var preBuildObject = new PreBuiltObjects(view, null, null);
|
||||
var inj = injector([NeedsPropertySetterNoType], null, null, preBuildObject);
|
||||
var component = inj.get(NeedsPropertySetterNoType);
|
||||
component.setProp('foobar');
|
||||
|
||||
expect(renderer.log[0]).toEqual([view.render, 0, 'title', 'foobar']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('static attributes', () => {
|
||||
it('should be injectable', () => {
|
||||
var attributes = MapWrapper.create();
|
||||
|
@ -190,7 +190,6 @@ export function main() {
|
||||
}));
|
||||
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
|
||||
ctx.ctxProp = 'a';
|
||||
view.detectChanges();
|
||||
|
||||
@ -591,6 +590,26 @@ export function main() {
|
||||
});
|
||||
}));
|
||||
|
||||
it('should support updating host element via hostProperties', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
template: '<div update-host-properties></div>',
|
||||
directives: [DecoratorUpdatingHostProperties]
|
||||
}));
|
||||
|
||||
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||
var injector = view.rawView.elementInjectors[0];
|
||||
var updateHost = injector.get(DecoratorUpdatingHostProperties);
|
||||
|
||||
updateHost.id = "newId";
|
||||
|
||||
view.detectChanges();
|
||||
|
||||
expect(view.rootNodes[0].id).toEqual("newId");
|
||||
|
||||
async.done();
|
||||
});
|
||||
}));
|
||||
|
||||
if (DOM.supportsDOMEvents()) {
|
||||
it('should support preventing default on render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||
tb.overrideView(MyComp, new View({
|
||||
@ -1047,6 +1066,20 @@ class DecoratorEmitingEvent {
|
||||
}
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
selector: '[update-host-properties]',
|
||||
hostProperties: {
|
||||
'id' : 'id'
|
||||
}
|
||||
})
|
||||
class DecoratorUpdatingHostProperties {
|
||||
id:string;
|
||||
|
||||
constructor() {
|
||||
this.id = "one";
|
||||
}
|
||||
}
|
||||
|
||||
@Decorator({
|
||||
selector: '[listener]',
|
||||
hostListeners: {'event': 'onEvent($event)'}
|
||||
|
Reference in New Issue
Block a user