使用UI-Router设置页面标题


101

我正在迁移基于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变量。


3
有一个$ stateChangeSuccess事件。
耶拉德

Answers:


108

$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已经所需的历史是正确的,至少在我测试过自己。


编辑:2014年11月24日-声明性方法:

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


超级棒。这想不出得到任何容易
马修·哈伍德

3
此示例也无法与历史记录一起正常使用(至少在Chrome 37中如此)。如果您处于各种状态之间,请查看您的历史记录,历史记录项目的标题将是前一页的值。如果您进入page1-> page2-> page3,然后查看历史记录,则page2的url将与page1的标题匹配。
jkjustjoshing 2014年

2
实际上,这不是很准确。页面标题在URL哈希值更改之前更改,因此浏览器认为新标题适用于旧页面。然后,后退按钮历史记录将关闭1页。element.text(title)在$ timeout中包装通话对我来说很有效。编辑原始帖子。
jkjustjoshing 2014年

3
如果标题需要根据某些url参数动态设置,则此方法将无效。
Kushagra Gour

10
@KushagraGour如果标题需要基于$ stateParams是动态的,则可以使用in函数resolve来生成它,然后在$ stateChangeSuccess事件期间使用以下命令访问“ resolved”值$state.$current.locals.resolve.$$values.NAME_OF_RESOLVE_FUNCTION
克劳斯·康拉德

91

通过将此处的大多数答案组合起来,还有另一种方法。我知道已经回答了,但是我想展示使用ui-router动态更改页面标题的方式。

如果您查看ui-router 示例应用程序,则它们使用angular .run块将$ state变量添加到$ rootScope。

// It's 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
比公认的答案更具说明性。我喜欢这个!
Endy Tjahjono 2014年

3
不知道如果我想在$ rootScope整个$范围对象只是为网页标题...
赫苏斯·卡雷拉

我不确定$ scope对象在@JesúsCarrera中被引用的位置
cwbutler 2015年

UPS,对不起,我的意思是$状态对象
赫苏斯·卡雷拉

4
只是为了确认github.com/angular-ui/ui-router/wiki/Quick-Reference还建议设置$state以及$stateParams$rootScope从内部run
Mark Peterson

17

角的UI路由器标题插件可以很容易地更新页面标题为静态动态的基础上,当前状态值。它也可以正确地与浏览器历史记录一起使用。


这似乎是未来的最佳解决方案。我注意到使用此页面上的其他一些解决方案与浏览器历史记录存在一些不一致之处。

angular-ui-router-title似乎确实是最好的解决方案。最重要的是没有麻烦!谢谢斯蒂芬。
达里奥

这是一个非常小的源文件。
Tyler Collier 2015年

15

$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}`;
    }
});

对于/bar/code/123将显示“条形码123”作为页面标题的URL路径。请注意,我正在使用ECMAScript 6语法格式化字符串并提取params.code

如果有时间的人将这样的内容放入指令中并发布给所有人使用,那就太好了。


data对象用于自定义键。接口title上不存在StateDeclaration
Gaui

5

将$ state附加到$ rootscope以在应用程序中的任何位置使用。

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

        // It's 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>


1
结合将其添加到每个州的标题。完美的作品。
WCByrne

5

我发现这种方式非常简单:

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

然后在我的HTML中是这样的:

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

5

只需更新window.document.title:

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

这样,“ ng-app”就不需要向上移动到HTML标记,而可以停留在主体上或更低的位置。


1
为什么这不是最佳答案?= /
rex

3

我正在使用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.'
    },
  })

2

实际上,您的第一个答案/问题真的很贴切。将标题添加为数据对象:

.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>

1

我最终得到了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; 
   });
});

如果没有任何与模板相关的内容,那么新开发者如何在不询问标题如何更改的情况下知道标题的更改?
ton.yeung 2015年

如果使用$ window.document.title,则$ timeout无效。我正在遵循这种技巧,只是为了摆脱$ timeout和$ digest的周期:)
Whisher

1

为什么不只是:

$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}}">

可能很难找出为什么/对于继承代码库的人来说标题是如何更改的
ton.yeung 2015年

为什么很难找出来?这个文档片断应该从一个指令被触发,说你的页面,titile =“。{{‘PAGETITLE’|翻译}}这个指令将被包含在每一页的第一个元素尼斯和声明明确
马丁

哦,通过编辑,我现在明白您的意思了。我的意思是说,一根衬板可以放在任何地方,$ rootscope,指令等...
ton.yeung 2015年

0

如果您使用的是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;

0

也许您可以尝试使用此指令。

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!');
    });

0

对于更新的UI-Router 1.0.0+版本,(https://ui-router.github.io/guide/ng1/migrate-to-1_0

请参考以下代码

app.directive('pageTitle', [
    '$rootScope',
    '$timeout',
    '$transitions',
    function($rootScope, $timeout,$transitions) {
        return {
            restrict: 'A',
            link: function() {
                var listener = function($transitions) {
                    var default_title = "DEFAULT_TITLE";
                    $timeout(function() {
                        	$rootScope.page_title = ($transitions.$to().data && $transitions.$to().data.pageTitle)
                            ? default_title + ' - ' + $transitions.$to().data.pageTitle : default_title;
                    	
                        
                    });
                };
                $transitions.onSuccess({ }, listener);
            }
        }
    }
])

将以下内容添加到index.html中:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.