parent
aabe83cf63
commit
883e1c1541
|
@ -514,7 +514,8 @@ Where:
|
||||||
* `some-element` Any element which can generate DOM events (or has an angular directive which generates the event).
|
* `some-element` Any element which can generate DOM events (or has an angular directive which generates the event).
|
||||||
* `some-event` (escaped with `()` or `bind-`) is the name of the event `some-event`. In this case the
|
* `some-event` (escaped with `()` or `bind-`) is the name of the event `some-event`. In this case the
|
||||||
dash-case is converted into camel-case `someEvent`.
|
dash-case is converted into camel-case `someEvent`.
|
||||||
* `statement` is a valid statement (as defined in section below).
|
* `statement` is a valid statement (as defined in section below).
|
||||||
|
If the execution of the statement returns `false`, then `preventDefault`is applied on the DOM event.
|
||||||
|
|
||||||
By default, angular only listens to the element on the event, and ignores events which bubble. To listen to bubbled
|
By default, angular only listens to the element on the event, and ignores events which bubble. To listen to bubbled
|
||||||
events (as in the case of clicking on any child) use the bubble option (`(^event)` or `on-bubble-event`) as shown
|
events (as in the case of clicking on any child) use the bubble option (`(^event)` or `on-bubble-event`) as shown
|
||||||
|
|
|
@ -391,6 +391,7 @@ export class Directive extends Injectable {
|
||||||
*
|
*
|
||||||
* - `event1`: the DOM event that the directive listens to.
|
* - `event1`: the DOM event that the directive listens to.
|
||||||
* - `statement`: the statement to execute when the event occurs.
|
* - `statement`: the statement to execute when the event occurs.
|
||||||
|
* If the evalutation of the statement returns `false`, then `preventDefault`is applied on the DOM event.
|
||||||
*
|
*
|
||||||
* To listen to global events, a target must be added to the event name.
|
* To listen to global events, a target must be added to the event name.
|
||||||
* The target can be `window`, `document` or `body`.
|
* The target can be `window`, `document` or `body`.
|
||||||
|
|
|
@ -131,17 +131,17 @@ export class AppView {
|
||||||
}
|
}
|
||||||
|
|
||||||
// implementation of EventDispatcher#dispatchEvent
|
// implementation of EventDispatcher#dispatchEvent
|
||||||
dispatchEvent(
|
// returns false if preventDefault must be applied to the DOM event
|
||||||
elementIndex:number, eventName:string, locals:Map<string, any>
|
dispatchEvent(elementIndex:number, eventName:string, locals:Map<string, any>): boolean {
|
||||||
):void {
|
|
||||||
// Most of the time the event will be fired only when the view is in the live document.
|
// 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
|
// However, in a rare circumstance the view might get dehydrated, in between the event
|
||||||
// queuing up and firing.
|
// queuing up and firing.
|
||||||
|
var allowDefaultBehavior = true;
|
||||||
if (this.hydrated()) {
|
if (this.hydrated()) {
|
||||||
var elBinder = this.proto.elementBinders[elementIndex];
|
var elBinder = this.proto.elementBinders[elementIndex];
|
||||||
if (isBlank(elBinder.hostListeners)) return;
|
if (isBlank(elBinder.hostListeners)) return allowDefaultBehavior;
|
||||||
var eventMap = elBinder.hostListeners[eventName];
|
var eventMap = elBinder.hostListeners[eventName];
|
||||||
if (isBlank(eventMap)) return;
|
if (isBlank(eventMap)) return allowDefaultBehavior;
|
||||||
MapWrapper.forEach(eventMap, (expr, directiveIndex) => {
|
MapWrapper.forEach(eventMap, (expr, directiveIndex) => {
|
||||||
var context;
|
var context;
|
||||||
if (directiveIndex === -1) {
|
if (directiveIndex === -1) {
|
||||||
|
@ -149,9 +149,13 @@ export class AppView {
|
||||||
} else {
|
} else {
|
||||||
context = this.elementInjectors[elementIndex].getDirectiveAtIndex(directiveIndex);
|
context = this.elementInjectors[elementIndex].getDirectiveAtIndex(directiveIndex);
|
||||||
}
|
}
|
||||||
expr.eval(context, new Locals(this.locals, locals));
|
var result = expr.eval(context, new Locals(this.locals, locals));
|
||||||
|
if (isPresent(result)) {
|
||||||
|
allowDefaultBehavior = allowDefaultBehavior && result;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
return allowDefaultBehavior;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,8 @@ export class RenderView {
|
||||||
this._eventDispatcher = dispatcher;
|
this._eventDispatcher = dispatcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatchEvent(elementIndex, eventName, event) {
|
dispatchEvent(elementIndex, eventName, event): boolean {
|
||||||
|
var allowDefaultBehavior = true;
|
||||||
if (isPresent(this._eventDispatcher)) {
|
if (isPresent(this._eventDispatcher)) {
|
||||||
var evalLocals = MapWrapper.create();
|
var evalLocals = MapWrapper.create();
|
||||||
MapWrapper.set(evalLocals, '$event', event);
|
MapWrapper.set(evalLocals, '$event', event);
|
||||||
|
@ -92,7 +93,11 @@ export class RenderView {
|
||||||
// out of action expressions
|
// out of action expressions
|
||||||
// var localValues = this.proto.elementBinders[elementIndex].eventLocals.eval(null, new Locals(null, evalLocals));
|
// var localValues = this.proto.elementBinders[elementIndex].eventLocals.eval(null, new Locals(null, evalLocals));
|
||||||
// this._eventDispatcher.dispatchEvent(elementIndex, eventName, localValues);
|
// this._eventDispatcher.dispatchEvent(elementIndex, eventName, localValues);
|
||||||
this._eventDispatcher.dispatchEvent(elementIndex, eventName, evalLocals);
|
allowDefaultBehavior = this._eventDispatcher.dispatchEvent(elementIndex, eventName, evalLocals);
|
||||||
|
if (!allowDefaultBehavior) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return allowDefaultBehavior;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -591,6 +591,23 @@ export function main() {
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
it('should support preventing default on render events', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
|
tb.overrideView(MyComp, new View({
|
||||||
|
template: '<input type="checkbox" listenerprevent></input><input type="checkbox" listenernoprevent></input>',
|
||||||
|
directives: [DecoratorListeningDomEventPrevent, DecoratorListeningDomEventNoPrevent]
|
||||||
|
}));
|
||||||
|
|
||||||
|
tb.createView(MyComp, {context: ctx}).then((view) => {
|
||||||
|
expect(DOM.getChecked(view.rootNodes[0])).toBeFalsy();
|
||||||
|
expect(DOM.getChecked(view.rootNodes[1])).toBeFalsy();
|
||||||
|
DOM.dispatchEvent(view.rootNodes[0], DOM.createMouseEvent('click'));
|
||||||
|
DOM.dispatchEvent(view.rootNodes[1], DOM.createMouseEvent('click'));
|
||||||
|
expect(DOM.getChecked(view.rootNodes[0])).toBeFalsy();
|
||||||
|
expect(DOM.getChecked(view.rootNodes[1])).toBeTruthy();
|
||||||
|
async.done();
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
it('should support render global events from multiple directives', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
it('should support render global events from multiple directives', inject([TestBed, AsyncTestCompleter], (tb, async) => {
|
||||||
tb.overrideView(MyComp, new View({
|
tb.overrideView(MyComp, new View({
|
||||||
template: '<div *if="ctxBoolProp" listener listenerother></div>',
|
template: '<div *if="ctxBoolProp" listener listenerother></div>',
|
||||||
|
@ -1162,6 +1179,30 @@ class DecoratorListeningDomEventOther {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Decorator({
|
||||||
|
selector: '[listenerprevent]',
|
||||||
|
hostListeners: {
|
||||||
|
'click': 'onEvent($event)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
class DecoratorListeningDomEventPrevent {
|
||||||
|
onEvent(event) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Decorator({
|
||||||
|
selector: '[listenernoprevent]',
|
||||||
|
hostListeners: {
|
||||||
|
'click': 'onEvent($event)'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
class DecoratorListeningDomEventNoPrevent {
|
||||||
|
onEvent(event) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: '[id]',
|
selector: '[id]',
|
||||||
properties: {'id': 'id'}
|
properties: {'id': 'id'}
|
||||||
|
|
Loading…
Reference in New Issue