fix(event): check hydration before firing event.

It is unlikely, but it can happen that an event is fired on a dehydrated
view. Extra guard asserts the events fire only on hydrated views.
This commit is contained in:
Rado Kirov 2015-01-15 12:36:56 -08:00
parent fb1b1da7b9
commit 2381c3640b
2 changed files with 54 additions and 1 deletions

View File

@ -381,10 +381,14 @@ export class ProtoView {
MapWrapper.forEach(binder.events, (expr, eventName) => { MapWrapper.forEach(binder.events, (expr, eventName) => {
DOM.on(element, eventName, (event) => { DOM.on(element, eventName, (event) => {
if (event.target === element) { if (event.target === element) {
// Most of the time the event will be fired only when the view is
// in the live document. However, in a rare circumstance the
// view might get dehydrated, in between the event queuing up and
// firing.
// TODO(rado): replace with // TODO(rado): replace with
// expr.eval(new ContextWithVariableBindings(view.context, {'$event': event})); // expr.eval(new ContextWithVariableBindings(view.context, {'$event': event}));
// when eval with variable bindinds works. // when eval with variable bindinds works.
expr.eval(view.context); if (view.hydrated()) expr.eval(view.context);
} }
}); });
}); });

View File

@ -403,6 +403,54 @@ export function main() {
}); });
}); });
describe('event handlers', () => {
var view, ctx, called;
function createViewAndContext(protoView) {
view = createView(protoView);
ctx = view.context;
called = 0;
ctx.callMe = () => called += 1;
}
function dispatchClick(el) {
DOM.dispatchEvent(el, DOM.createMouseEvent('click'));
}
function createProtoView() {
var pv = new ProtoView(el('<div class="ng-binding"><div></div></div>'),
new ProtoRecordRange());
pv.bindElement(new TestProtoElementInjector(null, 0, []));
pv.bindEvent('click', parser.parseBinding('callMe()', null));
return pv;
}
it('should fire on non-bubbling native events', () => {
createViewAndContext(createProtoView());
dispatchClick(view.nodes[0]);
expect(called).toEqual(1);
});
it('should not fire on a bubbled native events', () => {
createViewAndContext(createProtoView());
dispatchClick(view.nodes[0].firstChild);
// This test passes trivially on webkit browsers due to
// https://bugs.webkit.org/show_bug.cgi?id=122755
expect(called).toEqual(0);
});
it('should not throw if the view is dehydrated', () => {
createViewAndContext(createProtoView());
view.dehydrate();
dispatchClick(view.nodes[0]);
});
});
describe('react to record changes', () => { describe('react to record changes', () => {
var view, cd, ctx; var view, cd, ctx;
@ -583,6 +631,7 @@ class MyEvaluationContext {
foo:string; foo:string;
a; a;
b; b;
callMe;
constructor() { constructor() {
this.foo = 'bar'; this.foo = 'bar';
}; };