fix(ivy): coalesced listeners should preventDefault if any returns false (#29934)

We had a bug where event.preventDefault() was not always called if listeners
were coalesced. This is because we were overwriting the previous listener's
result every time we called the next listener, so listeners early in the chain
that returned false would be ignored and preventDefault would not be called.

This commit fixes that issue, so now preventDefault() is called if any listener
in a coalesced chain returns false. This brings us in line with View Engine
behavior.

PR Close #29934
This commit is contained in:
Kara Erickson
2019-04-16 12:02:42 -07:00
committed by Alex Rickabaugh
parent 86a3f90954
commit 1794a8e42a
2 changed files with 62 additions and 4 deletions

View File

@ -202,9 +202,11 @@ function listenerInternal(
}
}
function executeListenerWithErrorHandling(lView: LView, listenerFn: (e?: any) => any, e: any): any {
function executeListenerWithErrorHandling(
lView: LView, listenerFn: (e?: any) => any, e: any): boolean {
try {
return listenerFn(e);
// Only explicitly returning false from a listener should preventDefault
return listenerFn(e) !== false;
} catch (error) {
handleError(lView, error);
return false;
@ -242,7 +244,8 @@ function wrapListener(
// their presence and invoke as needed.
let nextListenerFn = (<any>wrapListenerIn_markDirtyAndPreventDefault).__ngNextListenerFn__;
while (nextListenerFn) {
result = executeListenerWithErrorHandling(lView, nextListenerFn, e);
// We should prevent default if any of the listeners explicitly return false
result = executeListenerWithErrorHandling(lView, nextListenerFn, e) && result;
nextListenerFn = (<any>nextListenerFn).__ngNextListenerFn__;
}