Get current route name in Ember - ember.js

I need to get the current route name in my ember application; I tried this:
Ember App.Router.router.currentState undefined
but it doesn't work for me (there is probablig something i'm missimg...) I use Ember rc6 and I have a multilingual app; in the applicationRoute I detect the browser's language and I redirect to the correct page with:
this.transitionTo(userLang);
but I would like this to be executed only when user are on the home page, so something like this:
if (currentRoute == 'home'){
this.transitionTo(userLang)
}

NOTE: as of Ember 3.16, the original answer is not only recommended, but observers are strongly discouraged.
To get the current route name, you can utilize the Router Service: https://api.emberjs.com/ember/3.18/classes/RouterService/properties/currentRouteName?anchor=currentRouteName
export default class MyComponent extends Component {
#service router;
get activeRoute() {
return this.router.currentRouteName;
}
}
Original answer below
You could observe the application's currentPath and set it to the current route accordingly when it changes:
App = Ember.Application.create({
currentPath: '',
});
App.ApplicationController = Ember.Controller.extend({
updateCurrentPath: function() {
App.set('currentPath', this.get('currentPath'));
}.observes('currentPath')
}),
This way you have access to the currentPath when ever you want with App.get('currentPath');
E.g.
if (App.get('currentPath') == 'home'){
this.transitionTo(userLang);
}
Hope it helps.

This worked for me on 1.3.0-beta (and a quick glance at the source for 1.1.2 suggests it would work there too):
App.__container__.lookup('router:main').location.lastSetURL
Note that the documentation states:
At present, it relies on a hashchange event existing in the browser.
However, I believe it's strongly suggested that App.__container__ not be used in production code. A more acceptable alternative would be to use App.Router.router.currentHandlerInfos, which provides information on the current Ember route.
Yet another option is currentRouteName on the ApplicationController. You can add needs: ['application'] to your controller, then access the route name with controllers.application.currentRouteName. This will return something like posts.index.

With the shift to components, it is harder to get route name. The best way is to add an initializer such as
ember g initializer router
(from command line), and
export function initialize(application) {
application.inject('route', 'router', 'router:main');
application.inject('component', 'router', 'router:main');
}
export default {
name: 'router',
initialize
};
in a initializers/router.js. You can also inject into controller if you need to. Then just do simply
this.get('router.currentRouteName');
in JS, or
{{router.currentRouteName}}
in template.
This is the only way I have found to get it reliably, and observable in Ember 2.4

If you want to get current route in your component or controller you can inject routing service (routing: Ember.inject.service('-routing'))
(for more) and use:
this.get('routing.currentRouteName') or this.get('routing.currentPath')
Example with component and computed property:
import Ember from 'ember';
export default Ember.Component.extend({
routing: Ember.inject.service('-routing'),
checkMyRouteName: Ember.computed('routing.currentRouteName', function() {
return this.get('routing.currentRouteName');
})
})
Example with controller and computed property:
import Ember from 'ember';
export default Ember.Controller.extend({
routing: Ember.inject.service('-routing'),
checkMyRouteName: Ember.computed('routing.currentRouteName', function() {
return this.get('routing.currentRouteName');
})
})
Current route in your route you just need this.routeName
Example with route:
import Ember from 'ember';
export default Ember.Route.extend({
checkMyRouteName() {
return this.routeName;
}
})

Just as an update, in Ember 1.8.1, we can get the routeName inside an Ember.Route object by doing this.routeName.

Currently as of Ember 1.7.0 you can get the current route from within a route by calling this.routeName.

The Ember namespace API now has a getOwner method, which is very useful for looking up the currentRouteName, or, other route properties.
const owner = Ember.getOwner(this);
const currentRoute = owner.lookup('router:main').currentRouteName;
const routeInfo = owner.lookup(`route:${currentRoute}`).get('info');
// etc.
I've created an Ember Twiddle example to demonstrate. Use the text input above the "Output" pane to hit other routes like /blue, /green, or /red.

Ember has a RouterService since 2.15. It provides the name of the current route as currentRouteName property. A polyfill exists for Ember 2.4 - 2.14 if you are still on such an old version.
import Component from '#ember/component';
export default Component.extend({
router: service(),
isHomeRoute: computed('router.currentRouteName', function() {
return this.router.currentRouteName === 'home';
}),
});
All other solutions mentioned here are relying on private API that might already be deprecated / removed. Using RouterService is working at least up the current version, which is 3.12 at the time of writing this.
Please note that the "home" is not /. The root URL is called "index".

I had the same problem for a while. then i started exploring router. It always have a state object which can be obtained from any route using
var route = this;
var handlerInfos = route.get("router.router.state.handlerInfos");
var currRouteHandlerInfo = handlerInfos[handlerInfos.length-1];
var currRouteName = currRouteHandlerInfo.name; //"home"
that's it. Now you have the current route name!
if you want the current route params,
var routerParams = this.get("router.router.state.params");
var currRouteParams = routerParams[currRouteName]; //{ homeId : "1" }

You can simple parse the current URL. This way you can use your full url for example:
http://127.0.0.1:8000/index.html/#/home
and extract from this string the suffix:
/home
which is the current route name.
A simple JS function (that works regardless to your Ember version) will be:
function getCurrentRoute()
{
var currentRoute;
var currentUrl = window.location.href; // 'http://127.0.0.1:8000/index.html/#/home'
var indexOfHash = currentUrl.indexOf('#');
if ((indexOfHash == -1) ||
(indexOfHash == currentUrl.length - 1))
{
currentRoute = '/';
}
else
{
currentRoute = currentUrl.slice(indexOfHash + 1); // '/home'
}
return currentRoute;
}
Example of use:
if (getCurrentRoute() == '/home')
{
// ...
}

Related

Shared data between various controllers

I have a project where I need to build an Ember application. The application will have many routes and some of the routes will have some model.
My problem at the moment is that some information is global, meaning they are present in each page (.hbs) and I need to update it periodically.
I've tried to put information on the application route like the following but it didn't work, the content is not accessible on other routes:
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return Ember.$.getJSON('/api/users/current')
}
});
I've also tried to reload the information with a setInterval but this didn't work either.
import Ember from 'ember';
export default Ember.Route.extend({
init: function() {
var thyself = this;
var interval = setInterval(function(){
thyself.my_reload()
}, 1000);
this.set('interval', interval);
this.set('counter', {});
},
my_reload: function() {
var counter = this.get('counter');
if (counter >= 10) {
clearInterval(this.get('interval'));
}
this.set('data', Ember.$.getJSON('/api/users/current'));
}
});
Where can I place this information so it will be available on all routes? And how can I reload the information periodically?
I'm using ember-cli
#NicosKaralis,
you should use service for it.
You can generate it by command: ember generate service name-of-service
And there you should create methods.
When you want to get access from your controller you should inject it in your controller:
nameOfService: Ember.inject.service(), (remember camelCase here)
and if you want some method from your service in your controller you will use it like this (example with computed property, you can also use it without computed property):
someComputedFunctionInController: Ember.computed(function() {
this.get('nameOfService').yourFunctionFromService();
},
nextComputedFunctionInController: Ember.computed(function() {
this.get('nameOfService.getSomethingFromService');
}
for more:
https://guides.emberjs.com/v2.7.0/tutorial/service/
Hope, it will help you.

Ember dependency injection not working with router in Ember 1.11

I have an ember component where I need both the store and the router. I'm trying to inject them using Ember.inject.service. It works when I inject the store, but not the router:
import Ember from 'ember';
const MyComponent = Ember.Component.extend({
store: Ember.inject.service('store'),
routing: Ember.inject.service('-routing'),
classNames: ['my-component'],
schema: Ember.computed('store', 'routing', function schema() {
// This works. Shows up when I log it.
const store = this.get('store');
// This doesn't
const routing = this.get('routing');
// return schema from store. This works.
}),
});
export default MyComponent
I'm on Ember version 1.11.3. Am I missing something?
I'm not sure about Ember 1.13, but in my Ember 2.x app, I inject the router as you described above and can then transition as follows:
this.get('routing.router').transitionTo('routeName', model, {
queryParams: {
queryName: queryValue
}
});
ps: It is generally considered best practice to pass an action closure into a component which would take care of the route transition, rather than making the component responsible for handling the transition.

Ember deprecation: replacing a view with a component

Hey I'm facing a problem with removing a view.
The view is used as navbar
{{view "inner-form-navbar" navbarParams=innerNavObject}}
Where params look like this
innerNavObject: {
...
routeToReturn: 'someroute.index',
...
},
On the navbar there's a small "back" button when it's clicked the parent index route is opened.
It currently works like this:
this.get('controller').transitionToRoute(routeToReturn);
But this won't work in a component and is sketchy anyways. Do i need to somehow inject router to component? Or has anyone gotten a solution for this? The navbar is used in so many places so adding a property to navbarObject to have certain action defined is not a really good solution imo.
Went for this solution :
export default {
name: 'inject-store-into-components',
after: 'store',
initialize: function(container, application) {
application.inject('component', 'store', 'service:store');
application.inject('component', 'router', 'router:main');
}
};
Now i can do
this.get('router').transitionTo('blah')
Well you can try to use a service that provides the routing capabilities and then inject into the component.
There's an addon that seems to do just that - ember-cli-routing-service
Example taken from the link, adapted for you scenario:
export default Ember.Component.extend({
routing: Ember.inject.service(),
someFunc () {
this.get('routing').transitionTo(this.get('innerNavObject'). routeToReturn);
}
});
Having a component control your route/controller is typically bad practice. Instead, you would want to have an action that lives on your route or controller. Your component can then send that action up and your route or controller will catch it (data down, actions up).
In your controller or route, you would have your transition action:
actions: {
transitionFunction(route) {
this.transitionTo(route);
}
}
You would also define the the current route name in your route or controller and pass that to your nav bar component. Controller could then look like:
export default Controller.extend({
application: inject.controller(),
currentRoute: computed('application.currentRouteName', function(){
return get(this, 'application.currentRouteName');
}),
actions: {
transitionFunction(route) {
this.transitionTo(route);
}
}
});
Then call your component and pass the currentRoute CP to it:
{{nav-bar-component currentRoute=currentRoute action='transitionFunction'}}
Then, in your component, you can have a function that finds the parent route from the currentRoute:
export default Component.extend({
click() { // or however you are handling this action
// current route gives us a string that we split by the . and append index
const indexRoute = get(this, currentRoute).split('.')[0] + '.index';
this.sendAction('action', indexRoute);
}
});
Extending a route
Per your comment, you may want to have this across multiple routes or controllers. In that case, create one route and have your others extend from it. Create your route (just as I created the Controller above) with the action. Then import it for routes you need:
import OurCustomRoute from '../routes/yourRouteName';
export default OurCustomRoute.extend({
... // additional code here
});
Then your routes will have access to any actions or properties set on your first route.

Ember transitionToRoute cleanly in a component without sendAction

How can transitionToRoute be called cleanly from within an Ember component?
It works with injecting a controller into the component and calling the controller's transitionToRoute function, however I'd like something a little more elegant if possible.
What it currently looks like inside the component's javascript:
// this.controller is injected in an initializer
this.controller.transitionToRoute("some.target.route.name");
What would be nicer in the component's javascript:
transitionToRoute("some.target.route.name");
One goal is do this without using sendAction as this particular component has a single purpose and should always transition to the same route. There's no need for any other Ember artifacts to be aware of the route this component always transitions to, there's no need for the associated indirection. The responsibility for the target route is owned by this component.
UPDATE Please see the other more recent answers for how to achieve this with less code in newer Ember versions, and vote those up if they work for you - Thanks!
Inject the router into the components and call this.get('router').transitionTo('some.target.route.name').
To inject the router into all components, write an initializer at app/initializers/component-router-injector.js with the following contents:
// app/initializers/component-router-injector.js
export function initialize(application) {
// Injects all Ember components with a router object:
application.inject('component', 'router', 'router:main');
}
export default {
name: 'component-router-injector',
initialize: initialize
};
Sample usage in a component:
import Ember from 'ember';
export default Ember.Component.extend({
actions: {
submit: function() {
this.get('router').transitionTo('some.target.route.name');
}
}
});
Jan 22, 2018 update
As of Ember 2.15, phase 1 of the public router service is implemented.
Transition to a route from inside a component:
import { inject as service } from '#ember/service';
export default Ember.Component.extend({
router: service(),
actions: {
someAction() {
this.get('router').transitionTo('index');
}
}
});
Use
router: service()
instead of
router: service('-routing')
import Component from '#ember/component';
import {inject as service} from '#ember/service';
export default Component.extend({
router: service(),
actions: {
onClick(params) {
let route = this.getMyRoute(params);
this.get('router').transitionTo(route);
}
}
});
If you want to use the router only in a specific component or service or controller, you may try this:
Initialize an attribute with the private service -routing. The - because it's not a public API yet.
router: service('-routing'),
And then inside any action method or other function inside the service or component:
this.get('router').transitionTo(routeName, optionalParams);
Note: It'll be transitionToRoute in a controller.
You can use container to get access to any needed part of application. To get application controller :
this.container.lookup('controller:application')
But what about structure of application - components should generate events - so my opinion it's better to use sendAction. Cause in future you can get situation, when you need to filter such behavior ( for example ) or other application-specific logic before transition

ember routing - pass param to child route where param will serve as filter param in store retrieval

I have a scenario where there are "jobaids" - jobaids belong to "businessunits", "systemapplications", and "courses" & finally "businessunits" have many of all of the above.
When entering the project you start on the "businessunits" route (#/businessunits), where they are listed as "#link-to"s they link to a show view and when clicked move you to #/businessunits/:businessunits_id
When you arrive on this template there is a an option to view the current "Businessunit"s related "Jobaids" by "systemapplication", "course" or just "show all"
Since the easiest place to start in consideration of the model relationships (and because I'm new with ember), is the "show all" option, and that's where I've started.
So - what I need to do is get the :businessunit_id in...
#/businessunit/:businessunit_id
to be seen by the processing in the
#businessunit/:businessunit_id/jobaids
...to be able to apply to that route, a model consisting of something like
this.store.find('jobaid', {businessunit_id: ID-FROM-PARENT-ROUTE})
so far I have...
/app/router.js
import Ember from 'ember';
import config from './config/environment';
var Router = Ember.Router.extend({
location: config.locationType
});
Router.map(function() {
this.resource("businessunits", function() {
this.route("show", { path: ":businessunit_id" }, function(){
this.resource("jobaids", function() {});
});
});
});
export default Router;
...and the "show all" link leading to the route where I need the value of the parent id is an actual anchor tag with an {{action "getJobaids"}} which is handled with the show in the /app/routes/businessunits.js route
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
return this.store.find('businessunit');
},
actions: {
getJobaids: function(){
var url = location.href.split('/');
window.unitClicked = url[url.length-1];
this.transitionTo('jobaids');
}
}
});
then when you get to /app/routes/jobaids.js we're getting the needed id from the window...
import Ember from 'ember';
export default Ember.Route.extend({
model: function(){
return this.store.find('jobaid', {businessunit_id: unitClicked});
}
});
this is TERRIBLE but this works enough to get me to the next route (where there are some other problems I have yet to figure out relating to querying the fixture and or adapter) - HOWEVER this is NOT a desirable fix and will never keep state, basically eventually resulting in missing (necessary) variables when linking back
#/businessunits/undefined/jobaids
which as you can imagine breaks everything - so how do I do this in the genuine ember fashion without depending on a hacky use of bare bones js?
I ended up taking the development of this project in the direction of having an actual database back end to query against and let the relationships in ember's data library handle the nested object structure to access the relations returned in the JSON structure.