Exposing the current state name with ui router

JavascriptAngularjsAngular Ui-RouterAngular Translate

Javascript Problem Overview


I'm trying to implement a language switcher where if a user clicks on "de" from any given page on an "en" side - it takes them to that page of the "de" side. If I console.dir the $state parameter, it exposes the values I'd want with the "current" property of the given $state. If I try to console.dir the $state.current to focus on the values I want, it only gives the parent state property (my current views are nested).

My current thinking is, I'm on url/en/content, and dynamically I can then have my lang navigation dynamically load the appropriate destination points into some kind of data attribute, pick those up with a custom directive where I'd initiate a "go to" and set my preferedLanguage value per angular-translate.

The key issue at the moment is exposing that $state name - again, when simply browsing $state the current object gives the values I'd want, but $current.state directly only gives the parent state.

If anyone has a better suggestion of how to do this (in a angular way - no custom cookie junk) I'm happy to take suggestions.

Thanks!

Update! CODE SAMPLES:

Object reference of my states:

var urlStates = {
	    en: {
		    home: {
			    name: 'home',
			    url: '/en',
			    templateUrl: 'templates/'+lang+'/home.html',
			    abstract: 'true'
		    },
		    home_highlights: {
			    name:'home.highlights',
			    url: '',
			    templateUrl: 'templates/'+lang+'/home.highlights.html'
		    },
		    home_social:
		    {
			    name: 'home.social',
			    url: '/social',
			    templateUrl: 'templates/'+lang+'/home.social.html'
		    },
		    home_map:
		    {
			    name: 'home.map',
			    url: '/map',
			    templateUrl: 'templates/'+lang+'/home.map.html'
		    }

		};

My States:

$stateProvider
	    .state(urlStates.en.home)
	    .state(urlStates.en.home_highlights)
	    .state(urlStates.en.home_social)
	    .state(urlStates.en.home_map);

	    $locationProvider.html5Mode(true);
	
})

Controller:

.controller('LandingPage', function($translate, $state){
	this.state = $state;
	this.greeting = "Hello";
});

And Lastly, the output I see in the dom:

With this.state = $state;

{
	"params": {},
	"current": {
		"name": "home.highlights",
		"url": "",
		"templateUrl": "templates/en/home.highlights.html" },
		"transition": null
}

With this.state = $state.current

{
	"name": "",
	"url": "^",
	"views": null,
	"abstract": true
}

Javascript Solutions


Solution 1 - Javascript

this is how I do it

JAVASCRIPT:

var module = angular.module('yourModuleName', ['ui.router']);

module.run( ['$rootScope', '$state', '$stateParams',
                      function ($rootScope,   $state,   $stateParams) {
	$rootScope.$state = $state;
	$rootScope.$stateParams = $stateParams;	
}
]);

HTML:

<pre id="uiRouterInfo">
      $state = {{$state.current.name}}
      $stateParams = {{$stateParams}}
      $state full url = {{ $state.$current.url.source }}    
</pre>

EXAMPLE

http://plnkr.co/edit/LGMZnj?p=preview

Solution 2 - Javascript

Answering your question in this format is quite challenging.

On the other hand you ask about navigation and then about current $state acting all weird.

For the first I'd say it's too broad question and for the second I'd say... well, you are doing something wrong or missing the obvious :)

 

Take the following controller:

app.controller('MainCtrl', function($scope, $state) {
  $scope.state = $state;
});

Where app is configured as:

app.config(function($stateProvider) {
  $stateProvider
    .state('main', {
        url: '/main',
        templateUrl: 'main.html',
        controller: 'MainCtrl'
    })
    .state('main.thiscontent', {
        url: '/thiscontent',
        templateUrl: 'this.html',
        controller: 'ThisCtrl'
    })
    .state('main.thatcontent', {
        url: '/thatcontent',
        templateUrl: 'that.html'
    });
});

Then simple HTML template having

<div>
  {{ state | json }}
</div>

Would "print out" e.g. the following

{ 
  "params": {}, 
  "current": { 
    "url": "/thatcontent", 
    "templateUrl": "that.html", 
    "name": "main.thatcontent" 
  }, 
  "transition": null
}

I put up a small example showing this, using ui.router and pascalprecht.translate for the menus. I hope you find it useful and figure out what is it you are doing wrong.

Plunker here http://plnkr.co/edit/XIW4ZE

 

Screencap


imgur

Solution 3 - Javascript

In my current project the solution looks like this:

I created an abstract Language State

$stateProvider.state('language', {
    abstract: true,
    url: '/:language',
    template: '<div ui-view class="lang-{{language}}"></div>'
});

Every state in the project has to depend on this state

$stateProvider.state('language.dashboard', {
    url: '/dashboard'
    //....
});

The language switch buttons calls a custom function:

<a ng-click="footer.setLanguage('de')">de</a>

And the corresponding function looks like this (inside a controller of course):

this.setLanguage = function(lang) {
	FooterLog.log('switch to language', lang);
	$state.go($state.current, { language: lang }, {
		location: true,
		reload: true,
		inherit: true
	}).then(function() {
		FooterLog.log('transition successfull');
	});
};

This works, but there is a nicer solution just changing a value in the state params from html:

<a ui-sref="{ language: 'de' }">de</a>

Unfortunately this does not work, see https://github.com/angular-ui/ui-router/issues/1031

Solution 4 - Javascript

Use Timeout

$timeout(function () { console.log($state.current, 'this is working fine'); }, 100);

See - https://github.com/angular-ui/ui-router/issues/1627

Solution 5 - Javascript

I wrapped around $state around $timeout and it worked for me.

For example,

(function() {
  'use strict';

  angular
    .module('app')
    .controller('BodyController', BodyController);

  BodyController.$inject = ['$state', '$timeout'];

  /* @ngInject */
  function BodyController($state, $timeout) {
    $timeout(function(){
      console.log($state.current);
    });
    
  }
})();

Solution 6 - Javascript

Its just because of the load time angular takes to give you the current state.

If you try to get the current state by using $timeout function then it will give you correct result in $state.current.name

$timeout(function(){
    $rootScope.currState = $state.current.name;
})

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmotleydevView Question on Stackoverflow
Solution 1 - JavascriptrnrneverdiesView Answer on Stackoverflow
Solution 2 - JavascriptMikko ViitalaView Answer on Stackoverflow
Solution 3 - JavascriptpaulView Answer on Stackoverflow
Solution 4 - JavascriptAVIView Answer on Stackoverflow
Solution 5 - Javascriptpoke19962008View Answer on Stackoverflow
Solution 6 - JavascriptGaurav AggarwalView Answer on Stackoverflow