-
-
Notifications
You must be signed in to change notification settings - Fork 408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Attribute Actions #100
Attribute Actions #100
Conversation
Can't we keep |
We either need to do what @mmun suggests (make
+1 for that. This eliminates one of the places where jQuery leaks into Ember's public API, making it hard to safely support alternatives or a jQuery-optional world. |
I think making the non-dashed versions break would be a mistake (there were a number of core team members suggesting "just use the DOM API's, its wonderful" for 1.13+). We could try to map the most common ones automatically with a deprecation/warning, but I think we need to continue to allow them to work... |
That's why I would favor upgrading them automatically, rather than disallowing them. What would be the semantic differences if we started treating |
I believe the main difference is the way they would bubble (changing to on-click means it would fire after any parent elements and today it fires first), but I'm not super concerned with that. I think upgrading with a warning/deprecation would be fine. |
|
||
```hbs | ||
{{! app/templates/components/my-input.hbs }} | ||
<input on-change={{action 'log' value='target.value'}} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer to deprecate value in favor of valuePath (which is what it actually is), but maybe that is a discussion for another issue/PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I think that is uncontroversial, just needs to happen. I suppose it should happen with these changes just for ergonomics, since this is where valuePath=
should become more commonly used.
👍 from me |
some quick thoughts as i read:
|
One thing I'd like to try and maintain is action bubbling up the active route tree. The router as a state machine being able to respond to actions differently in different states is hugely useful and powerful, so I'd like to call out here making sure that this is still possible however actions are invoked in the future (I've had some discussion with @rwjblue about this on slack not long ago). |
This doesn't directly impact that, though it does reduce the exposure of route actions directly from a template. I personally think that is a good thing, and a collaborating service (ala the routing service RFC) can be used as the entry point into the router's hierarchical action structure. In other words, I think that it is absolutely important to ensure that the router still has the ability to handle actions (and this does not change that functionality). However, I do not think that targeting the router directly from a template is a good thing (and this functionality will almost certainly be removed when we move to routable components and away from controllers). |
@stefanpenner some reactions:
From classic actions? This RFC does not suggest their immediate deprecation or removal. I would prefer to migrate the documentation and community to the new style of usage before adding the deprecation. My ideal timeline would be kebabs in 2.x, deprecation of classic in 2.x+1. Will update to make this recommendation explicit.
I think this is being raised elsewhere by @mmun and @ef4 as well. Needs some thought. I was not as concerned about it as y'all seem to be initially.
Will call out the fact that any non-function should throw via an assert.
:-( I'm not too excited about holding this work on a clear plan for webcomponents, so I would say no. We don't explicitly test or support web components for any other Ember features. IMO, webcomponent support and the changes that would happy to ensure it is a whole different RFC. Open to feedback. Perhaps there is something conservative, like attaching the event dispatching and additionally setting the property of @alexspeller I believe the architectural concerns you've raised are valid and shared in some form by core- But I also think they are more related to routable components than to this proposal. The trick of routable components is how we pass actions down to the component as attrs, and that needs to be RFC'd in the next routable components plan (once we get there). |
|
||
Kebab actions are lazy. If a kebab action of `on-flummux` is used, then Ember | ||
should listen for the event of `flummux` on the root element and dispatch | ||
that action when it fires. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I am reading correctly, this means that in a child component you would sendAction('flummux')
(or is it going to be just send
everywhere with the new API?).
I think this would be a welcome change in my book. To replicate as close to native browser look and feel, I currently use onSubmit
to listen for form components to mop up all the user input I need, but this is a bit awkward since it means writing sendAction('onSubmit')
from my form component. Twiddle Example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@rtablada I don't think this proposes anything different as far as you gist goes. "Ember should listen for the event" and in general "Event Management" applies to regular DOM elements, not components. I'll clarify this in the RFC.
You would continue to use sendAction
in a component. Eventually you will just be calling this.attrs['on-click']()
, however we don't teach that right now since it means using attrs
which are confusing on curly components (auto-mut).
You raise an interesting though regarding glimmer components though. In a glimmer component, given this proposal:
<my-input class="error" on-change={{action 'refresh'}} />
// app/components/my-input.js
export default Ember.GlimmerComponent.extend();
{{! app/templates/components/my-input.hbs }}
<input class="blue" on-mouse-move={{action 'click'}} />
The class
attribute is considered merged with the class
attribute of the component's root element (making it "blue error"
). However this application of an attr to the root element does not apply to the on-change
attribute. Instead that is treated as an argument to the object, and attaching event listeners is deemed something only under the control of the component.
I think the above is good and correct. A component invocation should not be able to add event listeners to the root element of the invoked component. I'll update the RFC to discuss this interaction with Glimmer components more closely.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mixonic good to know about just calling this.attrs['on-click']
.
Just a thought, maybe a fireOn
function in components that is a bit like:
fireOn(name, ...args) {
const eventName = `on-${name.dasherize()}`;
if (this.attrs[eventName]) {
this.attrs[eventName](...args);
}
}
I just watched Matt introduce this at Ember NYC, and it looks awesome. The one comment I had as a first-time observer of the api was, the value part of Matt made the point that <div {{action 'save' on='mouseOver'}}>Save</div> is a somewhat awkward api, since it has no equivalent in HTML. But it seems that the value part of <div on-mouse-over={{action 'log' value='target.value'}}>Save</div> suffers from the same problem. I understand adding this api would save users from needing to define a new action under the <input on-change={{action (mut firstName) value='target.value'}} /> but it seems we could solve the same problem by using nested s-expressions: <input on-change={{action (compose (mut firstName) (take 'target.value') ) }} /> If we can do this with existing primitives, I think there'd need to be a really compelling reason to introduce the new api. Also, while the functional composition approach might be slightly harder to explain to a newbie (and I'm not sure this is true), at least they're learning a general programming technique that they can use with their own helpers, rather than another Ember-specific api. |
@samselikoff could be off on this, but value on actions is already in ember and not part of this RFC. Not saying that a take helper is a bad idea but not sure if changing the semantics of value would be part of this RFC? |
Ah, was unaware. In that case of course I agree we shouldn't change semantics. However I would like to see a unified message around using (or not) using that api. |
Yup, here was the example I remember using it from. http://balinterdi.com/2015/08/29/how-to-do-a-select-dropdown-in-ember-20.html — On Fri, Oct 23, 2015 at 6:45 AM, Sam Selikoff [email protected]
|
ZOMG! Thank you! The biggest problem we have with the "classic actions" is there was no access to the events. We often position popovers at the site of the click. Since "classic actions" didn't provide the event, we frequently have to install manual click handlers. |
@bantic and I were brainstorming about some of the outstanding issues here yesterday. This is an adjustment to the RFC, and I'll make the changes later today. On not choosing the
|
I can absolutely guarantee that if I think asserting / warning is definitely the best option here. |
I disagree that is wrong to "hijack" Regardless, I am ok with |
Is it suggested that we hijack |
|
@mixonic while I do think that |
Can someone explain to me what change in semantics we're talking about by choosing onclick=? |
Because events managed by Ember are delegated from a listener on the body, there are slight changes in ordering if you attach handlers on your own. This JSBin demonstrates using action and onclick, and you can see that the order of the wrapper click event and the action/onclick attached function are not consistent. |
About the discussion about event delegation, I'm not convinced that discouraging the dashless version is a good idea. I guess that with Probably in that case using the I'm sure that there might be other examples where the non-delegated version has some advantage (predictable callback invocation perhaps?) |
I have further thoughts to add, raised in discussion at the last core meeting. Will add shortly! |
For what it's worth, we've discussed this at great length in core team meetings, and we're converging on a consensus to go with The It is probably worth revisiting how we do events for Ember 3.0, but we're not going to change how events are delegated to components in the middle of the 2.x cycle, and |
I think the argument I'd like to make it that it should be possible for an addon to completely swap out the eventing system in play without extensive hacks into Ember itself. What made jQuery eventing so powerful was that it wasn't just about fixing cross-browser issues. jQuery
But jQuery also fast paths handler resolutions attached with Which brings me to my main point: the state of eventing in the Ember ecosystem has hit a point I think approaches a deadly architecture flaw. This rundown is completely ignoring the fact that Eventing in Ember
If you consider
Most good devs I talk to have no idea the difference between Here's a demo of just how / when all these different methods would trigger. The current thinking is that "CSS Scope Invasion" is wrong. I'd argue that something pretty similar is going on in eventing right now. Handlers can signup to manage events from too many directions, and in too many ways, leading to too many conflicts. But because we've all come to rely on I strongly feel that Ember should either opt to manage eventing comprehensively, or opt to not manage it all, but instead open the door for addons to easily create comprehensive solutions of their own. What exactly this means for |
@runspired It would be very helpful to see a rundown of event object and bubbling inconsistencies in IE9+. Do you have any resources that would make a good read? |
@mixonic quite honestly, the best place is the source code for jQuery's eventing. |
@mixonic but I can make it a priority tomorrow to generate a comprehensive rundown from that code for easy consumption by the core team. |
@wycats in order to have something in 3.0 that is different I think work needs to be done to start migrating away from the jquery event dispatcher, much like we had the globals/module resolver. We will support 2 event dispatchers for a while. |
I've looked through
And haven't identified any IE9 issue that would block us from using native event APIs. The quirkiest thing seems to be |
I've pushed a significant number of edits to this RFC, and I encourage people to read it again. The introduction spells out the main direction pretty directly.
|
And another small update:
|
official API. | ||
* There are some very small code changes, but largely this is a | ||
messaging and documentation change. | ||
* These "attribute events" should use `element.addEventListener(eventName, handler, false)` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will update and attempt to make this clearer.
- Not all events have accessors. For example
onfocusin=
does not exist as a property (see #12676), thus it falls back to an attribute. See also discussion at https://github.com/emberjs/rfcs/pull/100/files#r46105178 - Setting the accessor leaves us with a poor merge strategy for glimmer component root elements. The attached
onclick=
from the invocation site would stop an internal attachment. Instead, if we translateon*
to useaddEventListener
the merge is fairly natural. - The patterns for web components to be passed actions is vague, but basically you can pass a function as a property or you can attach an event listener. Emitting events is suggested by some "pure" web component patterns, and of course an emitted event would not call the function Ember currently passes as a property. React has a similar issue. I suggest we install even listeners instead, making us compatible with the event pattern, but then also install a dispatcher as a property
newElement.onmousewobble = newElement.onmousewobble || (details) => { newElement.dispatchEvent('mousewobble', new CustomElement('mousewobble', details)); }
This would only support a single argument to be attached to the event as a property, but means the pattern of "DOM things emit with an event first" would apply to all web components, even those that want to leverage the more ergonomic API of calling a function over dispatching an event (at least by default).
For a webcomponent to dispatch an attached attribute action, it should use | ||
`dispatchEvent`. | ||
|
||
Glimmer components may (and this is specilation more than design) permit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/specilation/speculation
We discussed this at the F2F this weekend. I shared a few slides for discussion, you can read them here on slideshare, but they are nothing exciting. Some resolution: This RFC has helped identify difficult realities about how events listeners attach to different targets. Any This is a fairly fundamental difficultly. The Ember team will continue to look at the web component space and try to derive recommendations and strategies for developers, other frameworks, and standards to improve this. However in the near term:
Thanks for the time, thought, and commentary on this proposal! I hope to return with more ideas on how to improve built-in web component interoperability soon. |
@cibernox mentioned to me that is already creeping into docs: http://emberjs.com/api/classes/Ember.Templates.helpers.html#method_action |
Rendered
If I have missed a use-case of classic actions, please help me out by describing it!