ember.js: Input component does not accept documented event names
Is this intended behavior, or a bug?
A contributor fixed an issue with our checkbox examples in the Guides, and in testing their work, I found that none of the Input types accept dasherized names, or enter, unless you use the action handler. However, it stated in the guides that they do, and the API docs suggest it as well.
In a fresh 3.15 app:
@action
doSomething() {
alert('something')
}
This does not work:
<Input @type="text" @key-down={{this.doSomething}} />
This also does not work, even though there are no dashes:
<Input type="text" @enter={{this.doSomething}} />
This does not work:
<Input type="text" {{on "enter" this.doSomething}} />
This works:
<Input @type="text" @keyDown={{this.doSomething}} />
This works:
<Input @type="text" @enter={{action "doSomething"}} />
This works:
<Input @type="text" @key-down={{action "doSomething"}} />
This works:
<Input type="text" {{on "keydown" this.doSomething}} />
To do:
- figure out of this is a feature or a bug
- if it’s a bug, fix it
- update API docs with the correct syntax
- update the Guides with the correct syntax https://github.com/ember-learn/guides-source/issues/1254
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 7
- Comments: 23 (16 by maintainers)
@cah-briangantzler @kevinhinterlong
Actually it has nothing to do with the
fnhelper, the problem is caused by this line:https://github.com/emberjs/ember.js/blob/dbf4dd1fc183eaa7f1fb7ebf927c3a228fb0de0b/packages/%40ember/-internals/views/lib/mixins/text_support.js#L325
When passing actions to
<Input />withoutfnhelper, the action is actually a “Mutable Cell Object” (correct me if I’m using a wrong term), it exists asview.attrs.enter, the view in here is the<Input />component actually.This line checks if a found “action” (
view.attrs.enter) is actually a function, but apparently it isn’t. The real function exists on theview.attrs.enter.valueproperty and if you callview.attrs.enterdirectly, it will proxy this invocation to itsvalueinstead.If we wrap the action with
fnhelper, this line will pass and the action will be invoked correctly. Sofndoesn’t has any problem here, the problem is in the old<Input />component itself.UPDATE: My english is weak, in order to help you understand, I setup a similar demo like @kevinhinterlong did, and I set a breakpoint on the line I mentioned above:
(passing an action w/o
fnhelper)(passing an action w
fnhelper)To be clear, the previously documented approach is correct – i.e.
<Input @type="text" @key-down={{this.doSomething}} />. With modifiers now available, if you are listening to a native event, then the{{on}}modifier approach is probably preferable and more idiomatic.The “camel case” approach is not correct as it “works” by “overriding” the private event handling hook as arguments are simply “splatted” onto the component instance.
And to be extra clear, there is no “magic” with the casing and they are not interchangeable –
keyDownis hook inherited fromEmber.Componentintended for the implementation of the class to override, not for the consumer/invoker of the component. Since that name is taken (remember arguments and properties shares the same namespace inEmber.Component), the public API name for the callback arguments has to be different andkey-down(etc) was chosen. It’s a completely different property fromkeyDown. (In fact, the implementation of thekeyDownhook is what calls/dispatches thekey-downcallback.)As far as passing strings (
@enter="method") it part of the “sendAction” semantics and is deprecated and will be removed in 4.0.This should be fixed by https://github.com/emberjs/ember.js/pull/18997, which
should be released in 3.21 and should be backportedhas been released in 3.21 and backported into LTS 3.20 and 3.16.All the event names that always worked on the classic
{{input }}(prior to 3.10, which is the first release that supports<Input />) should also work on<Input/>and if one doesn’t it’s a bug.However, this is complicated by the fact that there are patterns that worked by accident. For example,
key-downis the supported event name, but it’s implemented internally with akeyDownmethod, so if you saykeyDown=you’re actually overwriting that internal method and it just happens to do the right thing. But overwriting internal methods is… not a good idea.(This is a great illustration for why glimmer components use
this.argsinstead of putting all the arguments directly onto the component instance. We learned from the mistake.)@pzuraq
fnis needed for some reasonhttps://ember-twiddle.com/5f8ccbbc5770f600e332a12b1ca81d3a?numColumns=2&openFiles=templates.components.input-helper-demo\.hbs%2Ccomponents.input-helper-demo\.js
@gvocale If you change your code to:
then it would work as you expected.
And
@key-upis exactly what the official document recommended way:The Additional work which mentioned in the above description is here:
https://github.com/emberjs/ember.js/blob/v3.16.3/packages/@ember/-internals/views/lib/mixins/text_support.js
and here is the reason why
@key-upwould trigger@enteras well:https://github.com/emberjs/ember.js/blob/v3.16.3/packages/@ember/-internals/views/lib/mixins/text_support.js#L195-L198
I can walk through you what happened, but I can not explain why it is behaving like that. I believe this is one of a few “mysterious” things that often make people confused and ember.js should fix them ASAP.
At last, I highly recommend rewriting your code to:
and actions could be written as :
Because this way should be last long enough, and I truly think it has a better consistency and easy to understand.