feat(compiler): added support for host actions

This commit is contained in:
vsavkin
2015-05-11 12:31:16 -07:00
parent a9ce0f7afb
commit f9c1de46b3
22 changed files with 330 additions and 17 deletions

View File

@ -17,7 +17,7 @@ import {ViewRef, Renderer} from 'angular2/src/render/api';
import {QueryList} from 'angular2/src/core/compiler/query_list';
class DummyDirective extends Directive {
constructor({lifecycle, events} = {}) { super({lifecycle: lifecycle, events: events}); }
constructor({lifecycle, events, hostActions} = {}) { super({lifecycle: lifecycle, events: events, hostActions:hostActions}); }
}
@proxy
@ -97,6 +97,13 @@ class HasEventEmitter {
}
}
class HasHostAction {
hostActionName;
constructor() {
this.hostActionName = "hostAction";
}
}
class NeedsAttribute {
typeAttribute;
titleAttribute;
@ -381,7 +388,7 @@ export function main() {
});
describe('event emitters', () => {
it('should return a list of event emitter accessors', () => {
it('should return a list of event accessors', () => {
var binding = DirectiveBinding.createFromType(
HasEventEmitter, new DummyDirective({events: ['emitter']}));
@ -392,6 +399,18 @@ export function main() {
expect(accessor.eventName).toEqual('emitter');
expect(accessor.getter(new HasEventEmitter())).toEqual('emitter');
});
it('should return a list of hostAction accessors', () => {
var binding = DirectiveBinding.createFromType(
HasEventEmitter, new DummyDirective({hostActions: {'hostActionName' : 'onAction'}}));
var inj = new ProtoElementInjector(null, 0, [binding]);
expect(inj.hostActionAccessors.length).toEqual(1);
var accessor = inj.hostActionAccessors[0][0];
expect(accessor.actionExpression).toEqual('onAction');
expect(accessor.getter(new HasHostAction())).toEqual('hostAction');
});
});
});

View File

@ -581,15 +581,37 @@ export function main() {
expect(listener.msg).toEqual('');
emitter.fireEvent('fired !');
PromiseWrapper.setTimeout(() => {
ObservableWrapper.subscribe(emitter.event, (_) => {
expect(listener.msg).toEqual('fired !');
async.done();
}, 0);
});
emitter.fireEvent('fired !');
});
}));
if (DOM.supportsDOMEvents()) {
it("should support invoking methods on the host element via hostActions", inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new View({
template: '<div update-host-actions></div>',
directives: [DirectiveUpdatingHostActions]
}));
tb.createView(MyComp, {context: ctx}).then((view) => {
var injector = view.rawView.elementInjectors[0];
var domElement = view.rootNodes[0];
var updateHost = injector.get(DirectiveUpdatingHostActions);
ObservableWrapper.subscribe(updateHost.setAttr, (_) => {
expect(DOM.getOuterHTML(domElement)).toEqual('<div update-host-actions="" class="ng-binding" key="value"></div>');
async.done();
});
updateHost.triggerSetAttr('value');
});
}));
}
it('should support render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new View({
template: '<div listener></div>',
@ -671,6 +693,7 @@ export function main() {
});
}));
if (DOM.supportsDOMEvents()) {
it('should support preventing default on render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
tb.overrideView(MyComp, new View({
@ -1218,6 +1241,24 @@ class DirectiveUpdatingHostProperties {
}
}
@Directive({
selector: '[update-host-actions]',
hostActions: {
'setAttr': 'setAttribute("key", $action["attrValue"])'
}
})
class DirectiveUpdatingHostActions {
setAttr:EventEmitter;
constructor() {
this.setAttr = new EventEmitter();
}
triggerSetAttr(attrValue) {
ObservableWrapper.callNext(this.setAttr, {'attrValue': attrValue});
}
}
@Directive({
selector: '[listener]',
hostListeners: {'event': 'onEvent($event)'}

View File

@ -31,6 +31,7 @@ import {AppViewManagerUtils} from 'angular2/src/core/compiler/view_manager_utils
export function main() {
// TODO(tbosch): add more tests here!
describe('AppViewManagerUtils', () => {
var metadataReader;
@ -71,6 +72,7 @@ export function main() {
'isExportingComponent' : false,
'isExportingElement' : false,
'getEventEmitterAccessors' : [],
'getHostActionAccessors' : [],
'getComponent' : null,
'getDynamicallyLoadedComponent': null,
'getHost': host
@ -154,11 +156,13 @@ export function main() {
var hostView = createView(hostPv);
var spyEventAccessor1 = SpyObject.stub({"subscribe" : null});
SpyObject.stub(hostView.elementInjectors[0], {
'getHostActionAccessors': [],
'getEventEmitterAccessors': [[spyEventAccessor1]],
'getDirectiveAtIndex': dir
});
var spyEventAccessor2 = SpyObject.stub({"subscribe" : null});
SpyObject.stub(hostView.elementInjectors[1], {
'getHostActionAccessors': [],
'getEventEmitterAccessors': [[spyEventAccessor2]],
'getDirectiveAtIndex': dir
});
@ -172,6 +176,36 @@ export function main() {
expect(spyEventAccessor2.spy('subscribe')).toHaveBeenCalledWith(hostView, 1, dir);
});
it("should set up host action listeners", () => {
var dir = new Object();
var hostPv = createProtoView([
createComponentElBinder(null),
createEmptyElBinder()
]);
var hostView = createView(hostPv);
var spyActionAccessor1 = SpyObject.stub({"subscribe" : null});
SpyObject.stub(hostView.elementInjectors[0], {
'getHostActionAccessors': [[spyActionAccessor1]],
'getEventEmitterAccessors': [],
'getDirectiveAtIndex': dir
});
var spyActionAccessor2 = SpyObject.stub({"subscribe" : null});
SpyObject.stub(hostView.elementInjectors[1], {
'getHostActionAccessors': [[spyActionAccessor2]],
'getEventEmitterAccessors': [],
'getDirectiveAtIndex': dir
});
var shadowView = createView();
utils.attachComponentView(hostView, 0, shadowView);
utils.attachAndHydrateInPlaceHostView(null, null, hostView, createInjector());
expect(spyActionAccessor1.spy('subscribe')).toHaveBeenCalledWith(hostView, 0, dir);
expect(spyActionAccessor2.spy('subscribe')).toHaveBeenCalledWith(hostView, 1, dir);
});
});
describe('attachViewInContainer', () => {