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イベントがあります。
Jerrad、2014年

回答:


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 2014

10
@KushagraGourタイトルが$ stateParamsに基づいて動的である必要がある場合は、関数を使用してタイトルresolveを生成し、$ stateChangeSuccessイベント中に「解決済み」の値にアクセスできます$state.$current.locals.resolve.$$values.NAME_OF_RESOLVE_FUNCTION
Claus Conrad

91

これを行うためのもう1つの方法は、すでにここにあるほとんどの答えを組み合わせることです。私はこれがすでに回答されていることを知っていますが、ui-routerを使用して動的にページタイトルを変更する方法を示したかったのです。

ui-router サンプルアプリを見ると、角度の.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全体$スコープオブジェクトを希望の場合
ヘスス・カレラ

私は確かに$スコープオブジェクトはJesúsCarrera@参照されているところはないよ
cwbutler

UPSは、申し訳ありません私は$状態オブジェクトを意味する
ヘスス・カレラ

4
github.com/angular-ui/ui-router/wiki/Quick-Referenceを確認するためだけに、内からの設定$state$stateParamsオンもお勧め$rootScopeしますrun
マークピーターソン

17

角度-UI-ルータタイトルのプラグインは、それが簡単にページのタイトルを更新することができ、静的または動的な現在の状態に基づいた値。ブラウザの履歴でも正しく動作します。


これが今後の最良の解決策のようです。このページの他のソリューションのいくつかを使用すると、ブラウザの履歴にいくつかの不整合があることに気付きました。

angular-ui-router-titleは最善の解決策のようです。何よりもそれは手間のかからないです!ステパンありがとう。
ダリオ

非常に小さなソースファイルです。
タイラーコリアー、2015

15

$stateChangeSuccess今されるUI-ルータ1.1で非推奨と、デフォルトでは無効。新しいものを使用する必要があります$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ように、関数の呼び出しに使用されるのは状態そのものであり、1つの引数は状態パラメータになります。

$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

$ rootscopeに$ stateをアタッチして、アプリの任意の場所で使用します。

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 '19

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

$ window.document.titleを使用する場合、$ timeoutは役に立ちません。$ timeoutと$ digestサイクルを取り除くために、私はこのハックをフォローしています:)
ウィシャー

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

なぜそれを見つけるのが難しいのでしょうか?your-page-titile = "{{'pageTitle' | translate}}のように、このスニップはディレクティブからトリガーする必要があります。このディレクティブは、すべてのページの最初の要素に含まれます。ニースで宣言的な明快さ
Martin

ああ、編集して、私はあなたが今何を言っているのか分かります。私が意味したことは、1つのライナーが$ rootscope、ディレクティブなど、どこにでも配置できる可能性があるということでした
ton.yeung

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>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.