Skip to content
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

Closed
wants to merge 5 commits into from
Closed

Routable Components RFC #38

wants to merge 5 commits into from

Conversation

@ef4
Copy link
Contributor

@ef4 ef4 commented Feb 27, 2015

RFC

@chancancode
Copy link
Member

@chancancode chancancode commented Feb 28, 2015

👏 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 promise hook (I would have called it model like the router, but that clashes with the property that holds the actual resolved value) where you can optionally implement and return a promise. If you did return a promise from the hook, it will put the component into the loading substate and render the component-name/loading template, if there is one. When the promise resolves, it will assign the resolved value to the model property and render the regular component-name template. If it rejects, it will render the component-name/error.

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 promise hook is actually just a regular computed property, so you just declare its dependencies like you normally would. When one or more of its dependencies changed, this will "re-fire", and the framework can just observe this computed property to determine whether the component has changed state.

To me, this feels very natural and aligns very well with other parts of the framework (unlike refreshModel, etc, which are special-occasion concepts that I need to learn).

Once we have asynchronous components, it may be tempting to handle
all data loading through them, eliminating traditional Routes, and
essentially moving the model hook onto Components.

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, <img> <audio> <video> <iframe> etc are all data-fetching async components – with window.fetch coming to browsers this should feel much more natural and second-nature over time.

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 promise hook is also interesting. Then perhaps {{outlet}}s are really just {{yield}}s (now you can yield variables, callbacks etc, perhaps it would get rid of some of the controllerFor/modelFor global-punch-through awkwardness). Maybe all the route need to do is just instantiate the WhateverRouteComponent, set all the params as attributes on it and let it figure out what to do (promise, substates and whatnot). Perhaps the component (or links, etc) will call setState on the component to change between its child states/routes/components/templates, and the router just observe
these states to change URL accordingly...

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 🙊

@workmanw
Copy link
Contributor

@workmanw workmanw commented Feb 28, 2015

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 controllerFor or componentFor? We have dozens of cases where a route needs to communicate with an ancestor resource's controller. Sometimes it's as simple as toggling state (like showing/hiding elements on when another route's active/deactivate are called). Other times those controllers house large reusable logic pertaining to their model's state.

Similarly, what about Ember.inject.controller or Ember.inject.component? Very similar to above, our controllers frequently contact parent resource controllers. This type of thing happens a lot with our global nav-bars. Different routes can add/remove/enable/disable different nav options. Also when a controller creates a new model and requires one or more ancestor models to build a relationship.


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.


Therefore, if you want to send an action from a component up to the Route that rendered it, you should pass an action handler function as one of your component's attributes.

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?


This RFC deprecates calling render outside of route transitions.

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.

@wycats
Copy link
Member

@wycats wycats commented Feb 28, 2015

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).

@ef4
Copy link
Contributor Author

@ef4 ef4 commented Feb 28, 2015

Yes, @wycats has hit on the main reason that I think Routes still needs to be a thing.

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.

@zeppelin
Copy link

@zeppelin zeppelin commented Feb 28, 2015

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?

@ef4
Copy link
Contributor Author

@ef4 ef4 commented Feb 28, 2015

@zeppelin Yes, definitely. We don't want everyone to need to rename their routes to contain dashes just became Web Component names need dashes.

@jerel
Copy link

@jerel jerel commented Feb 28, 2015

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:

  1. What about the use case of manipulating (filtering, sorting, etc) data before it is displayed? Sorting, filtering, etc used to be done in a route's ArrayController. Will the documented path be to create a service for this data or to do it in a parent component with the {{#each}}{{/each}} in that component's template?
  2. With async components is there something that will keep new developers from eliminating all routes except the application route and breaking the url behavior (back button) like so many other SPA frameworks allow?
@ef4
Copy link
Contributor Author

@ef4 ef4 commented Feb 28, 2015

@workmanw So we almost certainly don't want something like Ember.inject.component, because one of the key things about components is their isolation. They can be understood and re-rendered reliably precisely because all their incoming state comes via their attributes or via services.

Where you're using controllerFor or needs to access a parent controller, you would instead have the parent component explicitly pass attributes or action handlers downward.

Where you're using controllerFor or needs to access some completely separate controller elsewhere, that should probably become a shared service that is injected into both.

I should probably update the document to be explicit about the fate of controllerFor and modelFor. I think they go away entirely.

@ef4
Copy link
Contributor Author

@ef4 ef4 commented Feb 28, 2015

@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 model that is a list of people, it can derive a filteredPeople property to be rendered.

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.

@workmanw
Copy link
Contributor

@workmanw workmanw commented Feb 28, 2015

@ef4

Where you're using controllerFor or needs to access a parent controller, you would instead have the parent component explicitly pass attributes or action handlers downward.

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 needs and some of the routes use needs to get to the aforementioned controller. Now any controller can just do this.set('controllers.application.leftNavOpen', false');. But since I can't do needs and I can't do Ember.inject.component, where does that state live? How can components way down the chain change his application state.

@chancancode
Copy link
Member

@chancancode chancancode commented Feb 28, 2015

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).

I think that differentiation makes sense.

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.

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 before_action in Rails controllers vs what you do in the body of your controller action. You can technically just have one or the other, but that would be mega confusing.

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 {{ related-yelp-reviews }} component fetches a list of related reviews, and wants to reuse the {{ yelp-review }} component to display them. Since the list already has the data for displaying the reviews, you would want to pass those materialized models down instead of the IDs.

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 😄

@ef4
Copy link
Contributor Author

@ef4 ef4 commented Feb 28, 2015

@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 mut attributes explicitly. The benefit is that this is completely transparent and there's never any mystery about where a state change is coming from. The downside is that it does require each intermediate level to explicitly pass the value onward to its own children.

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.

@workmanw
Copy link
Contributor

@workmanw workmanw commented Feb 28, 2015

@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, controllerFor, modelFor, needs, Ember.inject.controller all made it easy to communicate top down and bottom up. It feels like this API proposal decouples and insulates the routes and components along the ancestry chain.

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.

@ef4
Copy link
Contributor Author

@ef4 ef4 commented Feb 28, 2015

@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.

@jesse-black
Copy link

@jesse-black jesse-black commented Feb 28, 2015

My questions:

  • Will it be possible to pass actions on the route to nested components without polluting the implementation of outer components to manually relay unrelated actions?
  • How will it handle reusable (from multiple routes) components that require operations on the ember-data store such as creating records? Right now the store is injected to controllers and we could create a controller to be reused from multiple routes. I assume the store won't be injected into components, so instead they will have to be handled on the top level application route if the components are to be used from multiple routes. It seems like this will lead to a bloated application route full of unrelated functionality to support multiple components like this.
@davidlormor
Copy link

@davidlormor davidlormor commented Mar 1, 2015

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 attributes hook vs. the current beforeModel, model, afterModel implementation with no clear way to "force" reload of model data.

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 think we need to publish more concrete details about services, because they are clearly critical for routeable components.

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.

@sandstrom
Copy link

@sandstrom sandstrom commented Mar 1, 2015

Interesting, I think this is great overall – very much looking forward to it!

Two thoughts:

  1. beforeModel has quite a few uses besides those mentioned in the RFC. One example is pausing to setup authentication[1], which must occur before calling the model hook. And moving that to say an initializer isn't ideal, because it's common that only certain routes are authenticated (requires auth).

    Will there still be a promise-aware hook to handle such cases?
    (if not I vote for keeping beforeModel)

    One great thing with Ember is that it's easy to customize (hooks are a part of this). Perhaps one could keep both beforeModel and afterModel (possibly under different names) since they have use-cases not directly tied to models.

  2. Under drawbacks it's mentioned that:

    "[it] makes the framework [..] opinionated about [...] Routes. For example, they can no longer render into outlets at arbitrary times."

    I think modals are commonly handled by having the application route (or another route) rendering into a specific 'modal outlet'. I don't have a clear idea of how that should be handled, but it would be great if that use-case is given some thought.

    I'm not a fan of modals and think they should be avoided, but to be fair they also have their use-cases.

[1] https://github.com/simplabs/ember-simple-auth/blob/master/packages/ember-simple-auth/lib/simple-auth/mixins/authenticated-route-mixin.js#L42

mitchlloyd added a commit to mitchlloyd/realtime-metro-web-client that referenced this pull request Mar 2, 2015
The loading message was showing when it shouldn’t have.

This can’t come soon enough: emberjs/rfcs#38
@tim-evans
Copy link

@tim-evans tim-evans commented Mar 2, 2015

I have a few thoughts around the mut keyword. First of all, it's strange to consider something mutable v. not mutable, since Ember doesn't use immutable objects. Is mutable the wrong word for what's being expressed here?

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 mut? For a developer like myself, it adds a lot of friction with development. I'm all on board with making Ember great for new devs, but handicapping experienced devs seems like it's not the right approach. I'm confident that I know whats mutating what, and I'm not scared of 3rd party addons that consume my data, for two reasons. 1) The pool of addons is small and 2) They can access any data in my app by rummaging through my app's container and registry.

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 👍 )

@slindberg
Copy link

@slindberg slindberg commented Mar 3, 2015

Huge thanks to @ef4 for tackling the most challenging of all changes in 2.0. 🍻

However, we can simplify all of this by moving the problem of avoiding model reloading into the data layer. ember-data is already capable of sufficiently intelligent caching.

I really like the idea of the model hook being idempotent; it makes complete sense take advantage of a data store's identity map. However I don't see this working well for routes that have model hooks that find record collections. For instance, say a route does something like this:

// 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 things.index route, a transition is triggered and all records are re-requested? Ember Data could do a slightly better job here of knowing if all records have been fetched previously, but the point still stands for things like store.findQuery({ ... }).

Therefore, we can collapse the three hooks down to a single model hook that always fires regardless of whether the transition references a model or an id

Does this mean that the first parameter to model is a params hash sometimes and a model other times? This seems backwards incompatible. EDIT: silly question

@kimroen
Copy link

@kimroen kimroen commented Mar 3, 2015

Does this mean that the first parameter to model is a params hash sometimes and a model other times? This seems backwards incompatible.

@slindberg I think this was referring to the way link-to, transitionTo and friends currently either fire or don't fire the model hook depending on if the passed in reference are params or a model, and that it will now fire either way. I don't think the parameters passed to model changes.

@slindberg
Copy link

@slindberg slindberg commented Mar 3, 2015

I don't think the parameters passed to model changes.

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 link-to or transitionTo.

@kimroen
Copy link

@kimroen kimroen commented Mar 3, 2015

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 link-to or transitionTo.

Yes, just like Ember.Route#serialize already does to construct the URL from the passed in model.

@ef4
Copy link
Contributor Author

@ef4 ef4 commented Mar 6, 2015

In response to @sandstrom 's question:

beforeModel has quite a few uses besides those mentioned in the RFC. One example is pausing to setup authentication[1], which must occur before calling the model hook.

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 beforeModel in the current system is that you couldn't rely on model always running.

@sandstrom
Copy link

@sandstrom sandstrom commented Mar 6, 2015

@ef4 I agree that's a way of solving it.

However, I like that Ember has hooks for common things, e.g. willDestroy, didInsertElement and didTransition. I think it's convenient with hooks for common things, instead of having to call this._super() in the model method of all child classes (needed if using a mixin or ancestor class).

I argue in favor of keeping these hooks.

@mitchlloyd
Copy link

@mitchlloyd mitchlloyd commented Mar 12, 2015

@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").

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.

I was planning to update that guide as soon as the foo={{action 'bar'}} syntax lands (it's noted on the Glimmer branch). Here is a hacky version: http://emberjs.jsbin.com/cisoko/5/edit?html,js,output

@2468ben
Copy link

@2468ben 2468ben commented Aug 11, 2015

@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.
Lots of changes are "mechanical" or easily explained in a few lines of blog post, but routeable components is a big one and the RFC hasn't been updated since February, so maybe there's a really quick update someone could give, even if it's "not sure yet". Something to tide us over for a few months until there's a blog post.

  • Currently planning to land in 2.2, 2.3 or later?
  • There was an announcement somewhere that a 'first step' landed in Canary, any link or short answer if that's for public use?
  • Is the routing service a pretty sure thing, and will it be pretty much like the old Router or something alongside it?
  • Anything else in the RFC you'd say has changed a lot and is worth mentioning? If there is, do you have a quick idea/suggestion for a 'prefactor' or pattern that might help ease the breaking change? Like "move your controller logic to a component if you want to get a headstart".
@ef4
Copy link
Contributor Author

@ef4 ef4 commented Aug 12, 2015

@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:

https://github.com/emberjs/ember.js/blob/5a023f33afa2cedb5a652cd2efd354352aa3d7c7/packages/ember-routing/lib/services/routing.js

It's not a replacement for the router, it's just a standardized way for components to communicate with the router.

@tomdale
Copy link
Member

@tomdale tomdale commented Aug 12, 2015

But I expect whatever we finally mark as public to be pretty similar.

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%.

@2468ben
Copy link

@2468ben 2468ben commented Aug 12, 2015

@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.
@konradjurk
Copy link

@konradjurk konradjurk commented Sep 16, 2015

Hey,
how can I pass initial attributes to a routable component?

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.

@knownasilya
Copy link
Contributor

@knownasilya knownasilya commented Sep 16, 2015

@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 attrs in render.

@ming-codes
Copy link

@ming-codes ming-codes commented Sep 23, 2015

I would love to see there's a way to pass arguments into {{outlet}}. This way it'll feel like the outlet actually is the routed component. Or rather, the {{outlet}} helper can just be like the {{component}} helper except the component name is supplied by the route.

{{#x-component as |yield1}}
  {{outlet param1=yield1}}
{{/x-component}}
@mellatone
Copy link

@mellatone mellatone commented Oct 14, 2015

@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.

@jcope2013
Copy link

@jcope2013 jcope2013 commented Oct 14, 2015

@mellatone there is an open RFC for one #95

@RGL9032
Copy link

@RGL9032 RGL9032 commented Mar 4, 2016

@chadhietala

Perhaps I should just wait 8 months like I did for HTMLBars.

@mixonic

I highly doubt they are 8 months out.

Surely it won't be another 8 months before Ember delivers on their promise, right? I mean Ember.View is being deprecated soon so surely we won't be left dangling without any guidance or insight on future direction. Ember would never do that to the devs who have supported them over the years ...

@locks
Copy link
Contributor

@locks locks commented Mar 4, 2016

@RGL9032 ember-legacy-views will be supported until Ember 2.8 LTS, if the refactoring work is concluded by then ("will likely be").
If you wish to continue supporting Ember, words of encouragement will be more effective. If you feel frustrated, imagine the core developers that are in the core specifically for their commitment to improving the framework.

@sandstrom
Copy link

@sandstrom sandstrom commented Mar 4, 2016

@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!

@buschtoens
Copy link
Contributor

@buschtoens buschtoens commented Apr 23, 2016

It would be super useful if attributes set on the {{outlet}} would be propagated to the component. Take CSS classes as an example.

@grapho
Copy link

@grapho grapho commented Apr 25, 2016

@buschtoens I imagine that case will be handled by classNames and/or classNameBindings on the routable component js

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

@mitchlloyd
Copy link

@mitchlloyd mitchlloyd commented Apr 26, 2016

@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 this.modelFor('parent') and model() or setupController() inside of a route to get access to a parent model inside of a template. We already have a natural API to pass attributes from a parent context into a component in our templates, why not for routable components?

{{route-component parent=parent}}
@grapho
Copy link

@grapho grapho commented Apr 26, 2016

@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 attributes() hook (confirm?). That is where you will be "passing in" the attributes and actions to the routable component.

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

@RGL9032
Copy link

@RGL9032 RGL9032 commented Nov 26, 2016

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 Ember-1.0 thru Ember-1.10 to Ember-2.0 thru Ember-2.10 it's night and day.

@ef4
Copy link
Contributor Author

@ef4 ef4 commented Nov 26, 2016

@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
@mirague
Copy link

@mirague mirague commented Mar 24, 2017

Routable components look very promising!

@wycats
Copy link
Member

@wycats wycats commented Jan 7, 2018

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:

  • Allowing a top-level template for a route to have a component class
  • Making it possible for routes to provide arguments to a its template other than model (and using the new @name syntax)
  • Making it possible to use query params in Ember without controllers

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

You can’t perform that action at this time.