1

I have an AngularJS web application. I would like to change page´s title dinamically. I would like the language configured is taken into account, so title should be displayed in different languages.

I successed to change the title dinamically when I navigate to different pages. I got the third approach of this post How to dynamically change header based on AngularJS partial view? which looked the most simple for me (I mean the one using $rootScope).

I have just an issue. When I´m on a page, let´s say index, and let´s suppose the language configuration is english, the title is displayed correctly in english. But If I change the language, in example to spanish (in a dropdown in navigation bar), the title does not change. If I navigate to another page, the title is correctly displayed in spanish.

Please find, the relevant code:

HTML:

<title ng-bind="title"></title>

EACH CONTROLLER:

.controller('HomeCtrl', function HomeCtrl($scope, $rootScope, $translate) {

        $rootScope.title = $translate('PAGE_TITLE_INDEX');
        ...
}


.controller ('AboutCtrl', function ($scope, $rootScope, $translate) {               

        $rootScope.title = $translate('PAGE_TITLE_ABOUT');
        ...
}

LANGUAGE SELECT DROPDOWN

<div ng-controller="LocationCtrl" style="padding-top: 5px">
            <select class="bootstrap-select-language show-tick" 
                    ng-change="changeLanguage(langKey)" 
                    ng-model="langKey" 
                    data-header="Choose your language..." 
                    ng-options="language.locale as language.name for language in translationLanguages"                  
                    bs-select
                    data-width="150px">                                  
            </select>           
        </div>

TRANSLATION FUNCTION IN CONTROLLER

$scope.changeLanguage = function (langKey) {
            $scope.langKey = langKey;
            $translate.uses(langKey);
            ...
}

UPDATE

I think for this scenario, the first approach in the above post is the right one (I mean, keeping the title in a service and get and set from the controllers). This way you can get the current title value in the translations controller and change it dinamically. Right?

Community
  • 1
  • 1
Rober
  • 5,812
  • 14
  • 48
  • 93
  • I´m using angular-translate. – Rober Feb 27 '15 at 09:08
  • I have wrote a module for these if you want to take a look https://github.com/AvraamMavridis/angular-metatags and use it in combination with angular-translate – Avraam Mavridis Feb 27 '15 at 10:17
  • Looks good! But have you tested it in combination with angular-translate? And how does the title in the browser look before everything is loaded? Will users see {{title}}? – Rober Feb 27 '15 at 11:57
  • I have tested with angular-translate. But you are right, for the title is not the best, since the users will see the {{title}} until everything is loaded. I am looking forward to find a solution on that and fix it. – Avraam Mavridis Feb 27 '15 at 15:05

2 Answers2

3

The approach you used should be fine. The <title> isn't changed because $translate.uses(langKey); doesn't change anything on the $rootScope. You can try this:

// i.e. for the HomeCtrl
$scope.changeLanguage = function (langKey) {
    $scope.langKey = langKey;
    $translate.uses(langKey);
    $rootScope.title = $translate('PAGE_TITLE_INDEX');
}

UPDATE: If you don't want to have the function in every controller, I think the most straightforward way with your current code base is:

angular.module('your-module')
.run(function($rootScope, $translate) {
    // serves as a cache
    var currentTitleKey = '';

    $rootScope.$on('changeTitle', function(e, titleKey) {
        // update if parameter is defined, else reuse
        currentTitleKey = (titleKey || currentTitleKey);

        $rootScope.title = $translate(currentTitleKey);
    });
});

Your page controller (i.e. HomeCtrl) would become:

// doesn't need $rootScope
$scope.$emit('changeTitle', 'PAGE_TITLE_INDEX');

And LocationCtrl would just do:

$scope.changeLanguage = function (langKey) {
    $scope.langKey = langKey;
    $translate.uses(langKey);
    // refresh current title
    $scope.$emit('changeTitle');
}
Kenny Ki
  • 3,170
  • 1
  • 21
  • 30
  • Mmm right, but maybe I didn´t provided the detail that the changeLanguage function is in its own controller (called LocationCtrl). Otherwise, I would need to duplicate the function in each controller or create a service. I mean, your example works, but always the changeLanguage is executed the "PAGE_TITLE_INDEX" is translated. Somehow the PAGE_TITLE should be injected, so PAGE_TITLE_ABOUT and other can be translated. So, I think you need to keep the PAGE_TITLE in service to be able to get it in changLanguage. What do you think? – Rober Feb 27 '15 at 10:51
  • Actually, your approach is right. But it´s another point I need the Title Page to be injected from somewhere else. – Rober Feb 27 '15 at 10:58
  • I don´t know why it´s not working for first time. I mean, the site is initially loaded in english. Then I change to Spanish and it´s not working, after that, I change to english (probably it´s working, but I don´t see any changes because it´s already in english), and then If I change to spanish it works. Any idea? – Rober Feb 27 '15 at 11:50
  • @Rober I'm not sure why it's not changing for the first time, try the updated solution and see if the problem persists – Kenny Ki Feb 27 '15 at 13:46
3

We have struggled through the many potential solutions. We are using Ionic, angular-translate, nested tabs, and are trying to change language on one page - and it is pushing the translated view-title onto the navbar. So we have removed all of the view-titles, $scope.$emits, and reduced it to a minimum (one rare case when working around a bug has led to less code):

Firstly, you can mix ng-bind and angular-translate statements like this - these will update whenever the language is changed with $translate.use(lang):

<html ng-app="myApp">
  <head>
    <title ng-bind="('SITE_TITLE' | translate) + ((pageTitle) ? ' - ' + (pageTitle | translate) : '')"></title>
    ....

When defining the states, set pageTitle within the data component to the appropriate translation key - do this for all non-abstract states, leave it undefined if you want a page to only show the SITE_TITLE:

  $stateProvider
    .state('tab.account', {
      url: '/account',
      views: {
        'tab-account': {
          templateUrl: 'app/account/tab-account.html',
          controller: 'AccountCtrl',
          controllerAs: 'account'
        }
      },
      data: {
        requireLogin: true,
        pageTitle: 'ACCOUNT_TAB_TITLE',
      }
    });

Within app.js configuration, inject $rootScope and set $rootScope.pageTitle in the $stateChangeStart event listener (or $stateChangeSuccess):

  $rootScope.$on('$stateChangeStart', function(event, toState, toParams, fromState, fromParams) {
    if (toState.data.pageTitle) {
      $rootScope.pageTitle = toState.data.pageTitle;
    }
  });

and, if using Ionic, remove all view-titles from templates (in our case we are using Ionic) and setting 'view-title' in the 'ion-view' meant that when you change language using an option select on our account page, the view-title was incorrectly applied to the nav-title... The following picks up data.pageTitle from the state and is much cleaner than what we had, and allows for pages where we set the nav-bar-title differently:

<ion-view>
  <ion-nav-title>{{pageTitle | translate}}</ion-nav-title>
Oliver Slay
  • 775
  • 7
  • 9