Deprecate transition methods of controller and route
Summary
The methods transitionTo
and replaceWith
of the Route
and the methods
transitionToRoute
and replaceRoute
of Controller
should be deprecated.
Existing methods transitionTo
and replaceWith
of RouterService
should
be used instead.
Motivation
The main motivation is to reduce public API surface related to routing. This will make the required refactoring of router easier as soon as the methods have been removed.
The router is known to be poorly documented and underspecified. Especially timing of the different APIs has been an issue in the past. Some timing related bugs are open since years.ยน
The implementation of Router#transitionTo
, Router#replaceWith
,
Controller#transitionToRoute
and Controller#replaceRoute
on one side and
RouterService#transitionTo
and RouterService#replaceWith
on the other side
are very different. Therefore it's very likely that they have different timings
in edge cases - even if that's not documented. Changing the timing of the
methods is considered a breaking change, which makes refactorings difficult.
Supporting different ways to do the same increases complexity without providing
much value. Especially if it's not only about true shortcuts. Supporting
transitions through RouterService
and <LinkTo>
component only will reduce
complexity for maintainers.
Additionally it reduces learning costs as new developers do not need to learn different APIs to do the same thing. The current guides showcase this issue by listing all four methods existing today and when they could be used:
It depends on where the transition needs to take place:
- From a template, use
as mentioned above - From a route, use the transitionTo() method
- From a controller, use the transitionToRoute() method
- From anywhere else in your application, such as a component, inject the Router Service and use the transitionTo() method
Deprecating Route#transitionTo
and Controller#transitionToRoute
will reduce
this list to two options without dropping any use case.
Naming RouterService
as the only option to trigger a transition in JavaScript
will also help with teaching Ember as a a component-service framework.
RouterService#transitionTo
and RouterService#replaceWith
are not only
available in Route
and Controller
but also in any services and components.
The current architecture might mislead developers not being aware of
RouterService
to bubble an action up to the controller or route in order to
trigger a transition. Or pass Controller#transitionToRoute
or
Controller#replaceRoute
methods down to a component as an argument.
Transition Path
Router#transitionTo
, Route.replaceWith
, Controller.transitionToRoute
and Controller.replaceRoute
should trigger a deprecation if being used.
The deprecation message should recommend using RouterService#transitionTo
or RouterService#replaceWith
instead.
// app/route/foo.js
import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
export default class FooRoute extends Route {
+ @service router;
@service session;
beforeModel() {
if (!this.session.isAuthenticated) {
- this.transitionTo('login');
+ this.router.transitionTo('login');
}
}
}
// app/controllers/foo.js
import Controller from '@ember/controller';
+ import { inject as service } from '@ember/service';
export default class FooController extends Controller {
+ @service router;
+
@action
async save({ title, text }) {
let post = this.store.createRecord('post', { title, text });
await post.save();
- return this.transitionToRoute('post', post.id);
+ return this.router.transitionTo('post', post.id);
}
}
A codemod should be provided, which replaces the usage of transitionTo
method
in any class that extends Route
and transitionToRoute
method in any class
that extends Controller
with this.router.transitionTo
. The same should be
done for Route#replaceWith
and Controller#replaceRoute
. Additionally the
RouterService
should be injected if needed.
In case consumers face timing issues while refactoring to
RouterService#transitionTo
and RouterService#replaceWith
they should change
their project to be compatible with the timing provided by these two methods.
The deprecation phase should be long enough to allow all applications to adopt.
For now it's assumed that it will be enough time for all relevant projects to
migrate before v5.0 release. The deprecation period might be increased if a
relevant number of projects weren't able to migrate before that date.
How We Teach This
The guides need to be updated to only use RouterService#transitionTo
,
RouterService#replaceWith
and <LinkTo>
component in order to trigger
a transition.
The routing guides list available option to transition between routes in
defining your routes chapter.
As already discussed in motivation section Route#transitionTo
and
Controller#transitionToRoute
should be removed from that list.
The redirecting chapter
of routing guides names Route#transitionTo
, Controller#transitionToRoute
and Route#replaceWith
as options to trigger a redirect. It doesn't mention
RouterService
yet at all. It also doesn't list Controller#replaceRoute
as
an option. This two paragraphs should be simplified by naming
RouterService#transitionTo
and RouterService#replaceWith
only.
The same applies to transitionTo paragraph of query parameters chapter
of routing guides. Instead of Route#transitionTo
and
Controller#transitionToRoute
only RouterService#transitionTo
should be
mentioned.
Additionally Route.transitionTo
is used in some code examples in the guides.
These should be changed to use RouterService#transitionTo
instead.
The deprecated methods should be marked as such in the API docs.
No changes to the tutorial are needed. Transitions in the tutorial are done
using <LinkTo>
component only.
Drawbacks
Route#transitionTo
is a highly used API in existing applications. Deprecating
it will very likely require changes to nearly all existing applications.
Using RouterService
instead of methods directly available on Route
or
Controller
requires explicit injection of router service. This could be seen
as boilerplate code.
Some editors are able to suggest methods which are available on a class
directly which is the case for Router#transitionTo
and the other methods
proposed for deprecation. This makes discovering them very easy. Discovering
methods only being available on services that need to be injected first, is not
that easy. Developers not being familar with the API might need to reach out
to guides or API docs to find them.
Deprecating (and later removing) these four methods will not enforce all
transitions to be triggered by either RouterService#transitionTo
,
RouterService#replaceWith
or <LinkTo>
. A transition could be still
triggered by setting a controller property, which is bound to a query
parameter. But this should be addressed in a separate RFC, which reworks
registration of query parameters in general.
Ember Engines injects Route#transitionToExternal
, Route#replaceWithExternal
and Controller#transitionToExternalRoute
methods. These methods allow the consumer to transition between routes external
to the engine. Ember Engines does not provide a service like RouterService
yet
to do this. But it's under active development.
Ember Engines uses the methods deprecated by this RFC to implement
Route#transitionToExternal
, Route#replaceWithExternal
and
Controller#transitionToExternalRoute
. This will trigger a deprecation warning
for all users of Ember Engines until Ember Engines is refactored to not use the
deprecated methods anymore.
While this RFC does not intend to decision how Ember Engines should address
the deprecations, it will very like force Ember Engines to deprecate
Route#transitionToExternal
, Route#replaceWithExternal
and
Controller#transitionToExternalRoute
de facto in mid-term for two reasons:
- These methods would not align anymore with the method provided by Ember to transition between routes.
- Ember Engines would not be able to change the implementations of these
methods to not use the methods deprecated by this RFC anymore. Using the
RouterService
would very likely change timing and other details of the methods, which could be seen as breaking changes. Keeping the current timings and other details would require usage of private method of the router.
Alternatives
Three possible alternative are discovered so far:
Instead of deprecating
Route#transitionTo
,Route#replaceWith
,Controller#transitionToRoute
andController#replaceWith
we could try to align their implementations to matchRouterService#transitionTo
andRouterService.replaceWith
in regards to timing and other details.Doing so will very likely require breaking changes as existing applications do very likely depend onto the existing timings and other details. Even if not being specified and documented these details became part of our public API over the years.
Therefore we would need to introduce an optional feature which allows applications to opt-in into the new timings as soon as they have verifed everything is working as expected.
We could introduce new methods on
Route
andController
, which are true shortcuts for usingRouterService
. This would prevent introducing the need to explicitly injectRouterService
inRoute
andController
in order to trigger a transition. As mentioned above this could be seen as boilerplate.Coming up with good names for these new methods would be challening as most of the names has been taken already. Additionally introducing new methods on
Controller
andRoute
will not help with reducing public API surface and teaching a component-service architecture.We could do nothing and continue the different ways to trigger a transition in JavaScript - including different timings and other details.
Unresolved questions
No open questions have been discovered so far.
Footnotes
- Some example for routing related bugs which are open for quite some time now:
https://github.com/emberjs/ember.js/issues/10262
https://github.com/emberjs/ember.js/issues/11152
https://github.com/emberjs/ember.js/issues/12945
https://github.com/emberjs/ember.js/issues/14875
https://github.com/emberjs/ember.js/issues/15801
https://github.com/emberjs/ember.js/issues/18416
https://github.com/emberjs/ember.js/issues/18577
https://github.com/emberjs/ember.js/issues/19037
This list does not contain a represantive list of bugs. Neither does it include bugs, which I verified myself. It's nothing more than a collection of bug reports that I found by searching for issues containing transitionTo in ember.js repository.