diff --git a/packages/@ember/-internals/glimmer/tests/integration/helpers/element-action-test.js b/packages/@ember/-internals/glimmer/tests/integration/helpers/element-action-test.js
index 6de7ff99412..50bad97f7da 100644
--- a/packages/@ember/-internals/glimmer/tests/integration/helpers/element-action-test.js
+++ b/packages/@ember/-internals/glimmer/tests/integration/helpers/element-action-test.js
@@ -712,6 +712,45 @@ moduleFor(
this.assert.equal(originalHandlerWasCalled, true, 'the click handler was called');
}
+ ['@test multiple actions with bubbles=false for same event are called but prevent bubbling']() {
+ let clickAction1WasCalled = false;
+ let clickAction2WasCalled = false;
+ let eventHandlerWasCalled = false;
+
+ let ExampleComponent = Component.extend({
+ actions: {
+ clicked1() {
+ clickAction1WasCalled = true;
+ },
+ clicked2() {
+ clickAction2WasCalled = true;
+ },
+ },
+ });
+
+ this.registerComponent('example-component', {
+ ComponentClass: ExampleComponent,
+ template: strip`
+ click me`,
+ click() {
+ eventHandlerWasCalled = true;
+ },
+ });
+
+ this.render('{{example-component}}');
+
+ runTask(() => {
+ this.$('a').trigger('click');
+ });
+
+ this.assert.ok(clickAction1WasCalled, 'the first clicked action was called');
+ this.assert.ok(clickAction2WasCalled, 'the second clicked action was called');
+ this.assert.notOk(eventHandlerWasCalled, 'event did not bubble up');
+ }
+
['@test it should work properly in an #each block']() {
let editHandlerWasCalled = false;
@@ -1359,6 +1398,40 @@ moduleFor(
this.assert.ok(doubleClickActionWasCalled, 'the doubleClicked action was called');
}
+ ['@test allows multiple actions for same event on a single element']() {
+ let clickAction1WasCalled = false;
+ let clickAction2WasCalled = false;
+
+ let ExampleComponent = Component.extend({
+ actions: {
+ clicked1() {
+ clickAction1WasCalled = true;
+ },
+ clicked2() {
+ clickAction2WasCalled = true;
+ },
+ },
+ });
+
+ this.registerComponent('example-component', {
+ ComponentClass: ExampleComponent,
+ template: strip`
+ click me`,
+ });
+
+ this.render('{{example-component}}');
+
+ runTask(() => {
+ this.$('a').trigger('click');
+ });
+
+ this.assert.ok(clickAction1WasCalled, 'the first clicked action was called');
+ this.assert.ok(clickAction2WasCalled, 'the second clicked action was called');
+ }
+
['@test it should respect preventDefault option if provided']() {
let ExampleComponent = Component.extend({
actions: {
diff --git a/packages/@ember/-internals/views/lib/system/event_dispatcher.js b/packages/@ember/-internals/views/lib/system/event_dispatcher.js
index 3af4a24536b..4070a52cdbd 100644
--- a/packages/@ember/-internals/views/lib/system/event_dispatcher.js
+++ b/packages/@ember/-internals/views/lib/system/event_dispatcher.js
@@ -285,13 +285,16 @@ export default EmberObject.extend({
return;
}
+ let result = true;
for (let index = 0; index < actions.length; index++) {
let action = actions[index];
if (action && action.eventName === eventName) {
- return action.handler(event);
+ // return false if any of the action handlers returns false
+ result = action.handler(event) && result;
}
}
+ return result;
};
// Special handling of events that don't bubble (event delegation does not work).