Установить заголовок страницы с помощью UI-Router

Я переношу приложение на основе AngularJS для использования ui-router вместо встроенной маршрутизации. Я настроил его как показано ниже.

.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider
    .state('home', {
        url: '/home',
        templateUrl : 'views/home.html',
        data : { pageTitle: 'Home' }

    })
    .state('about', {
        url: '/about',
        templateUrl : 'views/about.html',
        data : { pageTitle: 'About' }
    })
     });

Как я могу использовать переменную pageTitle для динамического определения названия страницы? Используя встроенную маршрутизацию, я мог бы сделать

$rootScope.$on("$routeChangeSuccess", function(currentRoute, previousRoute){
    $rootScope.pageTitle = $route.current.data.pageTitle;
  });

а затем привяжите переменную в HTML, как показано ниже

<title ng-bind="$root.pageTitle"></title>

Есть ли подобное событие, которое я могу подключить к использованию ui-router? Я заметил, что есть функции onEnter и onExit, но они, похоже, привязаны к каждому состоянию и потребуют от меня повторения кода для установки переменной $rootScope для каждого состояния.

Ответ 1

Используйте $stateChangeSuccess.

Вы можете поместить его в директиву:

app.directive('updateTitle', ['$rootScope', '$timeout',
  function($rootScope, $timeout) {
    return {
      link: function(scope, element) {

        var listener = function(event, toState) {

          var title = 'Default Title';
          if (toState.data && toState.data.pageTitle) title = toState.data.pageTitle;

          $timeout(function() {
            element.text(title);
          }, 0, false);
        };

        $rootScope.$on('$stateChangeSuccess', listener);
      }
    };
  }
]);

и

<title update-title></title>

Демо: http://run.plnkr.co/8tqvzlCw62Tl7t4j/#/home

Код: http://plnkr.co/edit/XO6RyBPURQFPodoFdYgX?p=preview

Даже если $stateChangeSuccess для истории был необходим $timeout, по крайней мере, когда я проверил себя.


Редактировать: 24 ноября 2014 г. - Декларативный подход:

app.directive('title', ['$rootScope', '$timeout',
  function($rootScope, $timeout) {
    return {
      link: function() {

        var listener = function(event, toState) {

          $timeout(function() {
            $rootScope.title = (toState.data && toState.data.pageTitle) 
            ? toState.data.pageTitle 
            : 'Default title';
          });
        };

        $rootScope.$on('$stateChangeSuccess', listener);
      }
    };
  }
]);

и

<title>{{title}}</title>

Демо: http://run.plnkr.co/d4s3qBikieq8egX7/#/credits

Код: http://plnkr.co/edit/NpzQsxYGofswWQUBGthR?p=preview

Ответ 2

Есть еще один способ сделать это, объединив большинство ответов здесь уже. Я знаю, что это уже ответили, но я хотел показать, как я динамически изменяю названия страниц с помощью ui-router.

Если вы посмотрите на ui-router примерное приложение, они используют angular .run, чтобы добавить переменную $state в $rootScope.

// It very handy to add references to $state and $stateParams to the $rootScope
// so that you can access them from any scope within your applications.
// For example, <li ng-class="{ active: $state.includes('contacts.list') }"> 
// will set the <li> to active whenever 'contacts.list' or one of its 
// decendents is active.

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

С помощью этого определения вы можете легко динамически обновлять заголовок своей страницы тем, что вы опубликовали, но модифицировали для использования определенного состояния:

Настройте состояние таким же образом:

.state('home', {
    url: '/home',
    templateUrl : 'views/home.html',
    data : { pageTitle: 'Home' }
})

Но отредактируйте html немного...

<title ng-bind="$state.current.data.pageTitle"></title>

Я не могу сказать, что это лучше, чем ответы раньше... но мне было легче понять и реализовать. Надеюсь, это поможет кому-то!

Ответ 3

Плагин angular-ui-router-title позволяет легко обновить заголовок страницы до статического или динамического значения на основе текущего состояния. Он также корректно работает с историей браузера.

Ответ 4

$stateChangeSuccess теперь устарел в UI-Router 1.x и отключен по умолчанию. Теперь вам нужно использовать новую службу $transition.

Решение не слишком сложно, если вы поймете, как работает $transition. Я получил помощь от @troig в понимании всего этого. Вот что я придумал для обновления названия.

Поместите это в свое приложение Angular 1.6. Обратите внимание, что я использую синтаксис ECMAScript 6; если вы этого не сделаете, вам понадобится, например, для изменения let на var.

.run(function($transitions, $window) {
    $transitions.onSuccess({}, (transition) => {
        let title = transition.to().title;
        if (title) {
            if (title instanceof Function) {
                title = title.call(transition.to(), transition.params());
            }
            $window.document.title = title;
        }
    });

Затем просто добавьте строку title в ваше состояние:

$stateProvider.state({
    name: "foo",
    url: "/foo",
    template: "<foo-widget layout='row'/>",
    title: "Foo Page""
});

Это заставит слова "Foo Page" появиться в названии. (Если состояние не имеет названия, заголовок страницы не будет обновлен. Было бы просто обновить приведенный выше код, чтобы предоставить заголовок по умолчанию, если состояние не указывает его.)

Код также позволяет использовать функцию для title. this, используемый для вызова функции, будет самим состоянием, а одним аргументом будут параметры состояния, например, этот пример:

$stateProvider.state({
    name: "bar",
    url: "/bar/{code}",
    template: "<bar-widget code='{{code}}' layout='row'/>",
    title: function(params) {
        return `Bar Code ${params.code}`;
    }
});

Для пути URL /bar/code/123, который будет отображать "Штрих-код 123" в качестве заголовка страницы. Обратите внимание, что я использую синтаксис ECMAScript 6 для форматирования строки и извлечения params.code.

Было бы неплохо, если бы кто-то, у кого было время, поставил бы что-то подобное в директиву и опубликовал его для всех, чтобы использовать.

Ответ 5

Присоединение $state к корневому файлу $для использования в любом месте приложения.

app.run(['$rootScope', '$state', '$stateParams',
    function ($rootScope,   $state,   $stateParams) {

        // It very handy to add references to $state and $stateParams to the $rootScope
        // so that you can access them from any scope within your applications.For example,
        // <li ng-class="{ active: $state.includes('contacts.list') }"> will set the <li>
        // to active whenever 'contacts.list' or one of its decendents is active.
        $rootScope.$state = $state;
        $rootScope.$stateParams = $stateParams;
    }
  ]
)
<title ng-bind="$state.current.name + ' - ui-router'">about - ui-router</title>

Ответ 6

Я нашел таким образом очень просто:

  .state('app.staff.client', {
    url: '/client/mine',
    title: 'My Clients'})

а затем в моем HTML:

<h3>{{ $state.current.title }}</h3>

Ответ 7

Просто обновите window.document.title:

.state('login', {
   url: '/login',
   templateUrl: "/Login",
   controller: "loginCtrl",
   onEnter: function($window){$window.document.title = "App Login"; }
})

Таким образом, "ng-app" не нужно перемещаться вверх по тегу HTML и оставаться на теле или ниже.

Ответ 8

Я использую ngMeta, что хорошо работает не только для определения названия страницы, но и для описания. Он позволяет вам установить конкретный заголовок/описание для каждого состояния, по умолчанию, когда название/описание не указано, а также суффиксы заголовков по умолчанию (т.е. "| MySiteName" ) и значение автора.

$stateProvider
  .state('home', {
    url: '/',
    templateUrl: 'views/home.html',
    controller: 'HomeController',
    meta: {
      'title': 'Home',
      'titleSuffix': ' | MySiteName',
      'description': 'This is my home page description lorem ipsum.'
    },
  })

Ответ 9

На самом деле вы действительно близки вашему первому ответу/вопросу. Добавьте свой заголовок в качестве объекта данных:

.state('home', {
    url: '/home',
    templateUrl : 'views/home.html',
    data : { pageTitle: 'Home' }
})

В вашем index.html привязать данные непосредственно к заголовку страницы:

<title data-ng-bind="$state.current.data.pageTitle + ' - Optional text'">Failsafe text</title>

Ответ 10

Почему не просто:

$window.document.title = 'Title';

ОБНОВЛЕНИЕ: полный код директивы

var DIRECTIVE = 'yourPageTitle';

yourPageTitle.$inject = ['$window'];
function yourPageTitle($window: ng.IWindowService): ng.IDirective {

    return {
        link: (scope, element, attrs) => {

            attrs.$observe(DIRECTIVE, (value: string) => {

                $window.document.title = value;
            });
        }
    }
}

directive(DIRECTIVE, yourPageTitle);

Затем на каждой странице вы просто включаете эту директиву:

<section
    your-page-title="{{'somePage' | translate}}">

Ответ 11

Я закончил эту комбинацию ответов Martin и tasseKATT - простой и без каких-либо связанных с шаблоном вещей:

$rootScope.$on("$stateChangeSuccess", function (event, toState) {
   $timeout(function () { // Needed to ensure the title is changed *after* the url so that history entries are correct.
     $window.document.title = toState.name; 
   });
});

Ответ 12

Если вы используете ES6, это работает отлично:).

class PageTitle {
    constructor($compile, $timeout) {
        this.restrict = 'A';
        this._$compile = $compile;
        this.$timeout = $timeout;
    }

    compile(element) {
        return this.link.bind(this);
    }

    link(scope, element, attrs, controller) {
        let defaultTitle = attrs.pageTitle ? attrs.pageTitle : "My Awesome Sauce Site";
        let listener = function(event, toState) {
            let title = defaultTitle;
            if (toState.data && toState.data.title) title = toState.data.title + ' | ' + title;
            $('html head title').text(title);
        };
        scope.$on('$stateChangeStart', listener);
    }
}

export function directiveFactory($compile) {
    return new PageTitle($compile);
}

directiveFactory.injections = ['$compile', '$timeout'];

export default PageTitle;

Ответ 13

Возможно, вы можете попробовать эту директиву.

https://github.com/afeiship/angular-dynamic-title

Вот пример:

HTML:

<title dynamic-title>Title</title>

<a href="javascript:;" ui-sref="state1">State1 page</a>
<a href="javascript:;" ui-sref="state2">State2 page</a>

JavaScript:

var TestModule = angular.module('TestApp', ['ui.router','nx.widget'])
    .config(function ($stateProvider, $urlRouterProvider) {
      //
      // For any unmatched url, redirect to /state1
      $urlRouterProvider.otherwise("/state1");
      //
      // Now set up the states
      $stateProvider
        .state('state1', {
          url: "/state1",
          templateUrl: "partials/state1.html",
          data:{
            pageTitle:'State1 page title11111'
          }
        })
        .state('state2', {
          url: "/state2",
          templateUrl: "partials/state2.html",data:{
            pageTitle:'State2 page title222222'
          }
        });
    })
    .controller('MainCtrl', function ($scope) {
      console.log('initial ctrl!');
    });