Skip to content

Commit

Permalink
[BUGFIX LTS] invoke methods correctly in TextSupport sendAction
Browse files Browse the repository at this point in the history
The introduction of the `attrs` API in Ember 3.13 included wrapping
items passed to components with `MutableCell`, to support two-way
binding. Although two-way binding is gone from much of Ember, the text
input components (`Input` and `Textarea`) continue to support it, via
the `TextSupport` mixins. The `sendAction` function used by the mixin
previously assumed that the only options were for an action to be a
string or a function -- not a function wrapped in a `MutableCell`.

The result was that this code, which would be expected to work, did not:
it would simply never be invoked.

    <Textarea @Focus-In={{this.didFocusIn}} />

Accordingly, add logic to `sendAction` in `text_support.js` to unwrap a
mutable cell if it is set, and otherwise to carry on with the logic as
it was previously.

Resolves #18994
  • Loading branch information
chriskrycho committed May 29, 2020
1 parent 4e8863e commit f16d174
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RenderingTestCase, moduleFor, runDestroy, runTask } from 'internal-test-helpers';

import { action } from '@ember/object';
import { assign } from '@ember/polyfills';
import { set } from '@ember/-internals/metal';
import { jQueryDisabled, jQuery } from '@ember/-internals/views';
Expand Down Expand Up @@ -780,6 +781,16 @@ moduleFor(
['@test sends an action with `<Input EVENT={{action "foo"}} />` for native DOM events']() {
this.assertTriggersNativeDOMEvents();
}

['@test triggers a method with `<Input @key-up={{this.didTrigger}} />`'](assert) {
this.render(`<Input @key-up={{this.didTrigger}} />`, {
didTrigger: action(function() {
assert.ok(true, 'action was triggered');
}),
});

this.triggerEvent('keyup', { keyCode: 65 });
}
}
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RenderingTestCase, moduleFor, runDestroy, runTask } from 'internal-test-helpers';

import { action } from '@ember/object';
import { assign } from '@ember/polyfills';
import { set } from '@ember/-internals/metal';
import { jQueryDisabled, jQuery } from '@ember/-internals/views';
Expand Down Expand Up @@ -631,6 +632,16 @@ moduleFor(
['@test sends an action with `{{input EVENT=(action "foo")}}` for native DOM events']() {
this.assertTriggersNativeDOMEvents();
}

['@test triggers a method with `{{input key-up=this.didTrigger}}`'](assert) {
this.render(`{{input key-up=this.didTrigger}}`, {
didTrigger: action(function() {
assert.ok(true, 'action was triggered');
}),
});

this.triggerEvent('keyup', { keyCode: 65 });
}
}
);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RenderingTestCase, moduleFor, classes, applyMixins, runTask } from 'internal-test-helpers';

import { action } from '@ember/object';
import { assign } from '@ember/polyfills';
import { set } from '@ember/-internals/metal';

Expand Down Expand Up @@ -209,5 +210,15 @@ moduleFor(
runTask(() => set(this.context, 'model', { val: 'A beautiful day in Seattle' }));
this.assertTextArea({ value: 'A beautiful day in Seattle' });
}

['@test triggers a method with `<Textarea @key-up={{this.didTrigger}} />`'](assert) {
this.render(`<Textarea @key-up={{this.didTrigger}} />`, {
didTrigger: action(function() {
assert.ok(true, 'action was triggered');
}),
});

this.triggerEvent('keyup', { keyCode: 65 });
}
}
);
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { RenderingTestCase, moduleFor, classes, applyMixins, runTask } from 'internal-test-helpers';

import { action } from '@ember/object';
import { assign } from '@ember/polyfills';
import { set } from '@ember/-internals/metal';

Expand Down Expand Up @@ -161,5 +162,15 @@ moduleFor(
runTask(() => set(this.context, 'model', { val: 'A beautiful day in Seattle' }));
this.assertTextArea({ value: 'A beautiful day in Seattle' });
}

['@test triggers a method with `{{textarea key-up=this.didTrigger}}`'](assert) {
this.render(`{{textarea key-up=this.didTrigger}}`, {
didTrigger: action(function() {
assert.ok(true, 'action was triggered');
}),
});

this.triggerEvent('keyup', { keyCode: 65 });
}
}
);
23 changes: 16 additions & 7 deletions packages/@ember/-internals/views/lib/mixins/text_support.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { get, set, Mixin } from '@ember/-internals/metal';
import { TargetActionSupport } from '@ember/-internals/runtime';
import { deprecate } from '@ember/debug';
import { SEND_ACTION } from '@ember/deprecated-features';
import { MUTABLE_CELL } from '@ember/-internals/views';

const KEY_EVENTS = {
13: 'insertNewline',
Expand Down Expand Up @@ -306,11 +307,19 @@ export default Mixin.create(TargetActionSupport, {
// sendAction semantics for TextField are different from
// the component semantics so this method normalizes them.
function sendAction(eventName, view, event) {
let actionName = get(view, `attrs.${eventName}`) || get(view, eventName);
let action = get(view, `attrs.${eventName}`);
if (action !== null && typeof action === 'object' && action[MUTABLE_CELL] === true) {
action = action.value;
}

if (action === undefined) {
action = get(view, eventName);
}

let value = get(view, 'value');

if (SEND_ACTION && typeof actionName === 'string') {
let message = `Passing actions to components as strings (like \`<Input @${eventName}="${actionName}" />\`) is deprecated. Please use closure actions instead (\`<Input @${eventName}={{action "${actionName}"}} />\`).`;
if (SEND_ACTION && typeof action === 'string') {
let message = `Passing actions to components as strings (like \`<Input @${eventName}="${action}" />\`) is deprecated. Please use closure actions instead (\`<Input @${eventName}={{action "${action}"}} />\`).`;

deprecate(message, false, {
id: 'ember-component.send-action',
Expand All @@ -319,14 +328,14 @@ function sendAction(eventName, view, event) {
});

view.triggerAction({
action: actionName,
action: action,
actionContext: [value, event],
});
} else if (typeof actionName === 'function') {
actionName(value, event);
} else if (typeof action === 'function') {
action(value, event);
}

if (actionName && !get(view, 'bubbles')) {
if (action && !get(view, 'bubbles')) {
event.stopPropagation();
}
}

0 comments on commit f16d174

Please sign in to comment.