-
-
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
Routable Components RFC #38
Conversation
👏 Great work! So just earlier today, I was mentioning the async component use case to @rwjblue and @ef4. A friend was asking for ideas on how to implement this, and he mentioned something along the lines of "you almost want a component with its own mini-route". That sounded bizarre at first, but as I think about it a bit more, it is starting to make a lot of sense. Of course, a "route" for a component doesn't make any sense. What we actually want is the "almost free" asynchrony handling and state management offered by the Ember router. Async and states are much more generic than the problem of routing, and since this approach worked out so well for routing, it makes a lot sense that you would desire the same kind of mechanisms in other places that you need to deal with these problems. So, I think I would be interested in something along the lines of http://emberjs.jsbin.com/bujufi/1/edit. Basically, like the router, you have a This is not a formal proposal, of course, and there are many nuances to be addressed. But overall, I feel that it fits in quite naturally with the rest of the framework. I would also like to draw your attention to this part of the code: App.YelpReviewComponent = Ember.Component.extend({
businessId: null, // Passed in
promise: function() {
if (this.get('businessId')) {
return GetYelpReview( this.get('businessId') );
} else {
return null;
}
}.property('businessId'),
...
}); The highlight is that the To me, this feels very natural and aligns very well with other parts of the framework (unlike
Is this really so bad? My gut feeling is that the routable component use case might just be a special case of async components. I think data-fetching async components should actually a pretty quite common thing, and the reason we aren't thinking/implementing them this way today is mostly just a side-effect of the poor ergonomics. If you think about it, So, I think it would need to have an a solid API for async components regardless. Since people need to learn/do that anyway, it is perhaps not a bad idea at all to put most of this responsibility (async management, substates) in the component, and implement routing in terms of async components. Most people coming from server-side MVC have NFI what a "route" object is (to be honest, I still don't know if I understand what it /really/ is, as opposed to just understanding how to use them), so I think it is not necessarily a bad thing if you can get away with not doing much at all with them in the 80% common cases. I am completely thinking out loud here, so bullshit alert on please. I feel like I am not smart enough to put together all the pieces, but there seems to be some interesting stuff in there somewhere. Substates, for example, are interesting. Since they don't actually change the URLs anyway (and in fact, we iterated a few times on whether they should eagerly update the URLs and stuff like that), it perhaps suggest that it is not intrinsically a routing concern. The CP + dependencies Anyway. I don't really have much concrete suggestions at the moment, and definitely haven't considered any backwards compatibility things at all. Just thought that I would throw this out there and let people smarter than me decide if it's pure snake oil or what 😄 I should also mention, it's almost 5AM here, so take it with many grains of salt 🙊 |
Thanks a lot! This is quite the RFC. Overall I'm pretty happy with how this shakes out. I love the idea of async components and the use of fragments. But I do have a few concerns based on app's usage of Ember. I've grouped them into sections below. These are grouped by priority of concern or impact to our application (biggest impact to smallest). What about Similarly, what about It's not clear from this RFC if actions will still exist as a hash on routes. It's also not clear if there will be any method of action bubbling on the route will exist. We have countless scenarios where we leverage action bubbling, anything sending realtime messages, to contextually handling alerts, to opening modal with different options depending on where the user is in the app. It would be a huge blow to loose action bubbling on routes.
We have near a hundred cases of controller actions that bubble to the route. Most of the time the action originates in a component and we want it to behave differently depending on where it is used in the app. This feels like it will add a lot of boilerplate. Storage for transient application state? We have some places in our app where we did get value from controllers being singletons. Where it was good to keep "temporary data". If you imagine Gmail, you can select a few emails, click to see the details of one, then navigate back and your selection is maintained. I know the goal of routes are to be stateless and I agree with that. I was just curious if there was a recommendation for this? Should I make a service just to store temp-selection?
We, like many other people, have been using this approach to modals: http://emberjs.com/guides/cookbook/user_interface_and_interaction/using_modal_dialogs/ This would break this pattern. That's okay with me, I didn't really love it. But I'm wondering if there is an alternative. Maybe using a ContainerView as modal manager. Thanks again! I hope this didn't come across as negative. I appreciate the amount of thought that went into this RFC by everyone and I'm excited to see this come to fruition. |
I really think it's important to differentiate between "I know what component I'm going to but I have work to do before I can show it" (async component) and "I have to do some work to do before I even know where I'm going" (route). |
Yes, @wycats has hit on the main reason that I think The problem with doing all the routing in components is that there is often important work to do before you can even establish a component hierarchy. Authorization decisions, for example, are really nicely done in routes. I think this will become even more significant as we work on lazily loading chunks of application. Routes are a natural place to manage decisions around what source code is even going to be needed, without having the components themselves present yet. |
Based on choice of words in the RFC is it safe to assume that naming routable components won't have to be consistent with the requirements of regular components - like how it proposed for fragments? |
@zeppelin Yes, definitely. We don't want everyone to need to rename their routes to contain dashes just became Web Component names need dashes. |
Since the 2.0 plan was announced I started focusing on components and services with minimal usage of controllers in my apps and I feel this RFC is well done and covers the pain points that I've felt. A couple questions I still have:
|
@workmanw So we almost certainly don't want something like Where you're using Where you're using I should probably update the document to be explicit about the fate of |
@jerel Any data manipulation an ArrayController was doing before can be done the same on the component instead. For example, if your component receives a Your second question is harder to answer. I agree that we don't want to make it easy to break the URL. We already run this risk today as people build their own ad-hoc asynchronous components, but by making asynchronous components easier we may get more of them, in scenarios that really should have been reflected in the URL. |
I guess the reason I struggle with this is because I don't know where this data would live. Like let's say I have a left nav that can be collapsed/expanded. Right now that is a boolean value on a controller high up in the ancestor chain. The controller for a leftnav uses |
I think that differentiation makes sense.
Those seems to be perfectly legit uses, too. I think, what I am really getting at is the former ("I have work to do before I can show it") seems like a very common need for components in general, not just routable ones. Therefore, it appears (again, I am very much just speculating) to be a nice thing to be able to reconcile and always use the same pattern in both the routable and non-routable cases, whatever that API ended up looking like. So, I agree there's very much still a need for routes. "80% common cases" is probably overstating it by a lot, but I mean "in the simple examples you see in the guides today (the blog app, or a github issue browser)", ideally you wouldn't/shouldn't have to touch the routes much, because those really just fall under "have work to do before I can show it". I agree with @wycats that those two are separate things, and I think they are currently too coupled/easily confused today. If we can encourage a good separation of the two (something like, "routing decision should go into the routes", "data fetching should be in the component"), that would make a lot of sense to me. This is basically the difference between what you put in your It could be that the work you to figure out your routing problems just so happens to give you the right data for display purposes, too. It should be possible to re-use those precious bits you downloaded for both purposes, but that feels it's technically more like an optimization (even though it is quite common) rather than the default way to reason about them ( => "since it's so common you should always do that in the routes"). By the way, I think the re-using data thing will be a problem outside of routable components, too. For example, in http://emberjs.jsbin.com/bujufi/1/edit, the I'm not sure if the strawman API in the jsbin is really that great of an idea to accomplish this, but I am just saying this would need to be solved anyway, and that solution (whatever it turned out to be) is probably reusable in this case. Edit: strawman Saturday – http://emberjs.jsbin.com/gadano/1/edit (The framework "implementation" is obviously just HAX to fake the strawman API.) Anyway! I don't usually look at or comment on these things, and I think my comments has very little to do with the concrete proposal you are making, so I hope they aren't too distracting from the real work that is going on here 😄 If this is counter-productive, I will very gladly move it to somewhere more appropriate 😄 |
@workmanw that's a good example. I see two possibilities, depending on your particular situation. The default thing to do when you want to share state from a parent component down to some children is to pass The second option is for cases where you have some widely-shared state that doesn't make sense to pass everywhere explicitly, and you create a service to manage it. Services are intended to be the well-defined escape hatch for sharing state "sideways" through the application. You could make a "leftNav" service that is injected into all the components that need it, and they can all read and write the shared state through the service. I think we need to publish more concrete details about services, because they are clearly critical for routeable components. |
Fix typos
@ef4 Thanks for the back and forth. The first option would not be desirable for us, it would just create too much boilerplate because we have so many cases where descendant controllers contact ancestor controllers. The second option would be more ideal for us, but I'm not exaggerating when I say that 2/3 of my routes would end up with their own services. It's possible that our app is in the minority, we have a lot of "dense" UI interactions, but the more I try to apply this API conceptually to our app, the more I feel like it's putting handcuffs on me. Things like action bubbling, Again, hopefully this doesn't come off as negative. I'm just trying to provide honest feedback based on our needs and how we've used Ember. Thanks a lot for hearing me out! See you guys at Emberconf. |
@workmanw your concerns are totally appropriate and valid. We absolutely need to make sure the API is great for those scenarios. This discussion is the whole point of publishing RFCs. |
My questions:
|
First off, let me say great job with RFC 👍 - this deals with some of the issues I've run into moving to a component-oriented structure (on v1.10 right now). In particular, async components is a much needed addition - this is a friction point I've run into many times now. Also, glad to see the transition to a singular Just wanted point out one method I've come across that never seems to be mentioned (this might be of use for @workmanw re: action bubbling). There seems to be quite a bit of confusion/worry/apprehensiveness in the discussions around having to explicitly pass in methods to a component. There is another way...although I seem to be the only one advocating this (wondering if I'm missing something...): using the 'targetObject' property allows you to access the current parent when a component is inserted into the DOM. The example that I use (a common pattern in my application) is the cancel button (JS Bin). As you can see, I don't have to pass in the action, but rather the action is fired from the component with assumption that it will be handled up the chain. Curious to hear any thoughts on this method of firing actions, and what might be done to improve upon this way of action "bubbling." Perhaps borrowing from the ideas presented in the Flux architecture about having a single "action dispatcher"? Also...very much this (from @ef4):
I can definitely see the value in the services concept, but details are vague at best around how they work...would be happy to help make them a "first-class citizen" if someone could point me in the right direction. |
Interesting, I think this is great overall – very much looking forward to it! Two thoughts:
|
The loading message was showing when it shouldn’t have. This can’t come soon enough: emberjs/rfcs#38
I have a few thoughts around the In addition, I'm not sure if I buy the use cases. Can someone explain to me the pain points that are solved by using I think the question here is, what perks do experienced Ember devs get out of this change? (Btw, I think this is great. Thanks for doing the hard work of formalizing this 👍 ) |
Huge thanks to @ef4 for tackling the most challenging of all changes in 2.0. 🍻
I really like the idea of the // app/routes/things/index.js
export default Ember.Route.extend({
model: function() {
return this.store.findAll('things');
}
}); Does this mean that when query params are updated on the
|
@slindberg I think this was referring to the way |
You're right, they just can't change. I guess this just means that the params will need to be extracted from the model when passed in via |
Yes, just like Ember.Route#serialize already does to construct the URL from the passed in model. |
In response to @sandstrom 's question:
As long as the model hook is always called, you can encapsulate that behavior inside the model hook itself: model: function(params) {
return setupMyAuthentication().then(() => MyModel.find(params));
} The only reason we had to have a separate |
@ef4 I agree that's a way of solving it. However, I like that Ember has hooks for common things, e.g. I argue in favor of keeping these hooks. |
@workmanw I think that particular modal pattern is going to be simpler now that we have better components and better thought technology around them ("data down actions up").
I was planning to update that guide as soon as the |
@mitchlloyd Thanks for the response, I honestly am fine with wherever Ember wants to go, and however they decide to get there. I've built a few frameworks before this but I decided to focus 100% on end products, and to work with whatever big tools are out there. I have zero disagreement with any architecture or implementation decision that Ember has made; my passion is using their great decisions to build my product. So instead of influencing the eventual routing service implementation, I really just want to know if there's something I could do to get 1.x code more compatible with the parts that are already ironed out.
|
@2468ben There is already a routing service in Ember, and has been for a while. It's just still marked private, because it needs a public design discussion before people start depending on it. But I expect whatever we finally mark as public to be pretty similar. See: It's not a replacement for the router, it's just a standardized way for components to communicate with the router. |
I don't think I can endorse that. As the person who worked on extracting the routing service from the existing code, there are still a lot of rough edges that I would like to get sanded down when working on the public routing service API. Feel free to use the private API, but I would peg the odds of code that relies on it breaking in a future release at close to 100%. |
@tomdale That's honestly great to hear, a "don't count on X" keeps me and others from refactoring because we keep hearing about X as the future. I think what I'm poking at above is if there's also "do count on X" for any bit of the Routeable Components RFC. It's mentioned constantly in Ember conversations as the future architecture and a set of big changes landing at any moment; I'm happy if the only update right now is "stay back, hide your children, nothing is certain". Or "this one tiny part will is definitely going in". We're all gonna refactor through umpteen deprecations, so while we're in there, any yes/nos on something solidifying since February could keep a lot of folks from planning based on the old RFC. Until then I'll just putt around a little more. |
Since the Element and Fragment RFC is contained in a separate branch of this repository - and ideally the link tracks with the latest version of the file - there's no straightforward way to have GitHub auto-link it (that I know of). So, this updates the Markdown link to go to the GitHub blob URL for the current Element and Fragment RFC.
Hey, The way which is described in the RFC (https://github.com/ef4/rfcs/blob/routeable-components/active/0000-routeable-components.md#specifying-component-attributes) seems not to work for me. Has something changed or has been implemented in a different way? I'm on 2.2.0-canary+851e4d1f and the routable-component feature flag is set to true. |
@berlincityboy according to the tests, it looks the same as it is now: https://github.com/emberjs/ember.js/blob/5351b9458f306398f6168acaa6f5eafe7a0bce2b/packages/ember/tests/routing/basic_test.js#L388 also see where the attrs are set here: https://github.com/emberjs/ember.js/blob/000a248921d0d121fb17d4665b66575fc4f6abb3/packages/ember-routing/lib/system/route.js#L2156 which is still using a controller and the old model hook. You could go around it by setting |
I would love to see there's a way to pass arguments into
|
@tomdale Is there a sense of where the public routing service is at? I feel that it is a pretty important aspect to routable components, and one that the community can gather around to move forward. The {{link-to}} helper has been something of a stand-in for older versions of Ember, but it only works in the simplest of use cases. |
@mellatone there is an open RFC for one #95 |
Surely it won't be another 8 months before Ember delivers on their promise, right? I mean |
@RGL9032 |
@RGL9032 there is a ton of effort behind Ember. Sure, a thing or two may have been slower out the door than initially expected, but that's pretty common with any project (open-source or not). I think Ember kept great pace recently! |
It would be super useful if attributes set on the |
@buschtoens comment retracted. i was corrected about classBindings. glimmer components wont work that way.. but there will be other ways to get the behavior you will need though |
@grapho Could you expand on those other ways? Feels odd to me that we wouldn't be able pass things from a template context into a routable component. One use case is where one would normally use {{route-component parent=parent}} |
@mitchlloyd tbh routable components are still fuzzy for me, i need to re-read some of the RFC and other videos I have seen. The final implementation is still undecided as far as I know. There are still many pieces missing before it can happen. What I have heard at least is, setupController() and the 3 model hooks will be replaced by a more semantic hook more specific to passing attrs into the routable component... something like an Will the route template contain an actual invocation to the routable component like your example above? Or perhaps a combination of the new attr hook and renderTemplate() as the original rfc suggests? or maybe the routable component's template itself will be responsible to setting things like classNames? I dont think there is a clear answer on any of that yet... otherwise it might already be more common knowledge. I have a feeling though it might be closer to option 3 though ;) ;) :P |
Is there anything that can be done to advance this? Is this still a goal for the core team? There is such a vacuum about the state of ember, the framework goals and the timeline for things. Engines and FastBoot are looking great and have gotten a lot of attention, but those features benefit primarily larger ember users. Glimmer 2 is also looking great, and it does benefit us all, but it's taken so much time and at this point it does not bring any new features beyond performance. Features like routable components, enhanced pods, routing service, and test unification are foundational improvements that benefit all of us. Beyond RFCs and old PRs, those features seem to be mostly stuck. What can the community at large do to help these goals move forward? I worry things have gotten so big and so complex that it's hard for the devs with only a few hours of availability to contribute. Additionally, with the bigger efforts like Glimmer 2 and Engines underway for months, I've sensed an unwillingness to take on medium and smaller features until the larger ones had completed. I definitely understand where that comes from, but some how we have to work past that. The amount of time that's gone into building larger features has me really worried for the future. Competing frameworks have done a much better job at iterating core parts of their API over the past 2 years, while ember has mostly focused on the edges. If you compare the framework changes from |
@RGL9032 we have more activity and contributors now than ever before. I agree that it takes time and effort to stay abreast of what's going on, but that's because there's so much of it, not so little. Please realize that when an account with no participation history jumps onto an old RFC to complain even though three major initiatives are "looking great", that doesn't leave much productive room for a helpful response. If you have only "a few hours" but want to help I suggest spending that time looking through the latest notes to see what's already ongoing and who is working on it, and using that are a starting point to talk to the people involved in areas that interest you. |
Fix the link to the Element and Fragment RFC
Routable components look very promising! |
This RFC was opened more than three years ago and literally predates the release of Ember 2.0. At the time, we were in the process of removing Ember 1.x-era "views", and we finally did eliminate legacy support for them after Ember 2.4. During the end of the 1.x timeframe, we deprecated and removed a lot of features very quickly. We also introduced a series of React-inspired data-flow APIs in Ember 1.13 (the last release of Ember 1.x) that became canonical APIs in Ember 2.0. While we were making all of these changes, we assumed that we would quickly deprecate controllers and unify the concept of controllers with components. There are two reasons that didn't happen. First, soon after Ember 2.0, we very quickly came to regret the pace of changes in the Ember 1.13 era, and resolved to avoid doing anything similar again. This more-or-less meant that any plans we had to continue deprecating, removing and consolidating features around that time were put on hold. The community had enough churn, and we wanted to let things settle before creating any more. Second, Ember 1.13 introduced the first version of Glimmer, and at the time we were highly optimistic that the Glimmer 1 architecture would make it easy to implement Glimmer components (with angle bracket invocation) quickly. We assumed that the new "routeable components" would want to default to the new "Glimmer component" semantics in the case where a routeable component didn't have a JavaScript class, which at the time, made it seem that routeable components blocked on finishing the Glimmer component work. Unfortunately, my personal work attempting to implement Glimmer components quickly ran into roadblocks, which ultimately led to the Glimmer 2 work, which resulted in a rather large and time consuming initiative. Between our desire to avoid introducing churn in the early 2.x era and the fact that our efforts in the view layer got redirected into implementing and integrating the Glimmer 2 engine, our ideas for routeable components in that era got put on the shelf. So much time has gone by since then, and the Glimmer architecture has evolved so much, that the original ideas that we had at the time aren't even relevant anymore. And in fact, the term "routeable component" has become a punchline that is permanently tainted with the long and sordid history of the exact details of this feature. I think that we should still do a series of features with these characteristics:
But I don't think we should call that feature "routeable components" and I don't think that feature shares much in common with the thinking we had at the time @ef4 originally wrote this RFC. I also think that we should look to emulate @chancancode's recent work in breaking down Glimmer component into multiple chunks when we work on this feature. Instead of one monolithic, entangled feature, I think we should break it apart into small bite-sized chunks we can land a bit at a time. Finally, with @chancancode's latest work breaking apart the Glimmer component feature (#276, #278, #280), I no longer believe that allowing a route's template to have a component blocks on Glimmer components (but there are some design questions, like what should happen if a route has both a controller and a component, and whether it should be allowed at all). For all of these reasons, I'm closing this RFC. |
RFC