Setel judul Halaman menggunakan UI-Router


101

Saya memigrasi aplikasi berbasis AngularJS saya untuk menggunakan ui-router alih-alih perutean bawaan. Saya sudah mengonfigurasi seperti yang ditunjukkan di bawah ini

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

Bagaimana saya dapat menggunakan variabel pageTitle untuk menyetel judul halaman secara dinamis? Dengan menggunakan perutean bawaan, saya bisa melakukannya

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

dan kemudian mengikat variabel dalam HTML seperti yang ditunjukkan di bawah ini

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

Apakah ada peristiwa serupa yang bisa saya hubungkan dengan menggunakan ui-router? Saya perhatikan bahwa ada fungsi 'onEnter' dan 'onExit' tetapi tampaknya terkait dengan setiap status dan akan meminta saya mengulangi kode untuk menyetel variabel $ rootScope untuk setiap status.


3
Ada acara $ stateChangeSuccess.
Jerrad

Jawaban:


108

Gunakan $stateChangeSuccess.

Anda dapat memasukkannya ke dalam petunjuk:

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);
      }
    };
  }
]);

Dan:

<title update-title></title>

Demo: http://run.plnkr.co/8tqvzlCw62Tl7t4j/#/home

Kode: http://plnkr.co/edit/XO6RyBPURQFPodoFdYgX?p=preview

Bahkan dengan $stateChangeSuccessyang $timeouttelah dibutuhkan untuk sejarah menjadi benar, setidaknya ketika saya telah menguji diri saya sendiri.


Edit: 24 Nov 2014 - Pendekatan deklaratif:

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);
      }
    };
  }
]);

Dan:

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

Demo: http://run.plnkr.co/d4s3qBikieq8egX7/#/credits

Kode: http://plnkr.co/edit/NpzQsxYGofswWQUBGthR?p=preview


Sangat bagus. Ini tidak bisa lebih mudah
Matthew Harwood

3
Contoh ini juga tidak berfungsi dengan baik dengan riwayat (setidaknya di Chrome 37). Jika Anda pergi di antara berbagai negara bagian, lalu lihat riwayat Anda, judul item riwayat akan menjadi nilai halaman sebelumnya. Jika Anda pergi ke halaman1 -> halaman2 -> halaman3, kemudian lihat riwayat, url halaman2 akan dicocokkan dengan judul halaman1.
jkjustjoshing

2
Sebenarnya, itu tidak cukup akurat. Judul halaman berubah sebelum hash URL berubah, jadi browser menganggap judul baru untuk halaman lama. Sejarah tombol kembali kemudian 1 halaman off. Membungkus element.text(title)panggilan dengan $ timeout berhasil bagi saya. Mengedit postingan asli.
jkjustjoshing

3
Ini tidak akan berfungsi jika judul harus dinamis berdasarkan beberapa parameter url.
Kushagra Gour

10
@KushagraGour Jika kebutuhan judul menjadi dinamis berdasarkan $ stateParams, Anda bisa menggunakan fungsi dalam resolveuntuk menghasilkan itu, kemudian mengakses "diselesaikan" nilai selama $ acara stateChangeSuccess dengan: $state.$current.locals.resolve.$$values.NAME_OF_RESOLVE_FUNCTION.
Claus Conrad

91

Ada cara lain untuk melakukan ini dengan menggabungkan sebagian besar jawaban di sini. Saya tahu ini sudah dijawab tetapi saya ingin menunjukkan cara saya mengubah judul halaman secara dinamis dengan ui-router.

Jika Anda melihat aplikasi sampel ui-router , mereka menggunakan blok angular .run untuk menambahkan variabel $ state ke $ 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;
}])

Dengan ini didefinisikan, Anda kemudian dapat dengan mudah memperbarui judul halaman Anda secara dinamis dengan apa yang telah Anda posting tetapi dimodifikasi untuk menggunakan status yang ditentukan:

Siapkan negara bagian dengan cara yang sama:

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

Tapi edit html-nya sedikit ...

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

Saya tidak bisa mengatakan ini lebih baik dari jawaban sebelumnya ... tetapi lebih mudah bagi saya untuk memahami dan menerapkan. Semoga ini bisa membantu seseorang!


3
Lebih deklaratif daripada jawaban yang diterima. Saya suka ini!
Endy Tjahjono

3
Tidak yakin apakah saya ingin seluruh objek $ scope di $ rootScope hanya untuk judul halaman ...
Jesús Carrera

Saya tidak yakin di mana objek $ scope direferensikan @ JesúsCarrera
cwbutler

Ups, maaf maksud saya objek $ state
Jesús Carrera

4
hanya untuk mengkonfirmasi github.com/angular-ui/ui-router/wiki/Quick-Reference juga merekomendasikan pengaturan $statedan $stateParamspada $rootScopedari dalam run.
Mark Peterson

17

The sudut-ui-router-judul Plugin memudahkan untuk memperbarui judul halaman ke statis atau dinamis nilai berdasarkan kondisi saat ini. Ini berfungsi dengan benar dengan riwayat browser juga.


Ini tampaknya menjadi solusi terbaik ke depan. Saya telah memperhatikan beberapa ketidakkonsistenan dengan riwayat browser yang menggunakan beberapa solusi lain di halaman ini.

angular-ui-router-title tampaknya menjadi solusi terbaik. Yang terpenting, ini bebas repot! Terima kasih Stepan.
Dário

Ini adalah file sumber yang sangat kecil.
Tyler Collier

15

$stateChangeSuccesssekarang tidak digunakan lagi di UI-Router 1.x dan dinonaktifkan secara default. Sekarang Anda harus menggunakan $transitionlayanan baru .

Solusi tidak terlalu sulit setelah Anda memahami cara $transitionkerjanya. Saya mendapat bantuan dari @troig untuk memahami semuanya. Inilah yang saya dapatkan untuk memperbarui judul.

Taruh ini di aplikasi Angular 1.6 Anda. Perhatikan bahwa saya menggunakan sintaks ECMAScript 6; jika tidak, Anda perlu misalnya pindah letke 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;
        }
    });

Kemudian tambahkan saja titlestring ke status Anda:

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

Itu akan membuat kata-kata "Foo Page" muncul di judul. (Jika suatu negara bagian tidak memiliki judul, judul halaman tidak akan diperbarui. Ini akan menjadi hal yang sederhana untuk memperbarui kode di atas untuk memberikan judul default jika suatu negara tidak menunjukkannya.)

Kode juga memungkinkan Anda menggunakan fungsi untuk title. The thisdigunakan untuk memanggil fungsi akan menjadi negara sendiri, dan satu argumen akan menjadi parameter negara, seperti contoh ini:

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

Untuk jalur URL /bar/code/123yang akan menampilkan "Bar Code 123" sebagai judul halaman. Perhatikan bahwa saya menggunakan sintaks ECMAScript 6 untuk memformat string dan mengekstrak params.code.

Alangkah baiknya jika seseorang yang punya waktu akan memasukkan sesuatu seperti ini ke dalam arahan dan menerbitkannya untuk digunakan semua orang.


Gunakan dataobjek untuk kunci khusus. titletidak ada di StateDeclarationantarmuka.
Gaui

5

Melampirkan $ state ke $ rootscope untuk digunakan di mana saja dalam aplikasi.

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
Gabungkan ini dengan menambahkan judul ke setiap negara bagian. Bekerja dengan sempurna.
WCByrne

5

Saya menemukan cara ini sangat mudah:

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

dan kemudian di HTML saya seperti ini:

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

5

Cukup perbarui window.document.title:

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

Dengan begitu 'ng-app' tidak perlu naik ke tag HTML dan bisa tetap di body atau lebih rendah.


1
Mengapa ini bukan jawaban terbaik? = /
rex

3

Saya menggunakan ngMeta , yang berfungsi dengan baik tidak hanya untuk menyetel judul halaman tetapi juga deskripsi. Ini memungkinkan Anda menetapkan judul / deskripsi tertentu untuk setiap negara bagian, default ketika judul / deskripsi tidak ditentukan, serta sufiks judul default (yaitu, '| MySiteName') dan nilai pengarang.

$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

Anda sebenarnya sangat dekat dengan jawaban / pertanyaan pertama Anda. Tambahkan judul Anda sebagai objek data:

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

Di index.html, ikat data langsung ke judul halaman:

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

1

Saya berakhir dengan kombinasi jawaban Martin dan tasseKATT ini - sederhana dan tanpa hal-hal terkait template:

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

jika tidak ada hal-hal yang berhubungan dengan template, bagaimana seorang pengembang baru tahu bagaimana judul diubah tanpa bertanya bagaimana itu diubah?
ton.yeung

jika Anda menggunakan $ window.document.title $ timeout tidak berguna. Saya mengikuti hackish ini hanya untuk menghilangkan $ timeout dan $ digest cycle :)
Whisher

1

Mengapa tidak hanya:

$window.document.title = 'Title';

UPDATE: Kode Petunjuk Lengkap

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);

Kemudian di setiap halaman Anda hanya akan memasukkan arahan ini:

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

berpotensi sangat sulit untuk mengetahui mengapa / bagaimana judul berubah untuk siapa saja yang mewarisi basis kode
ton.yeung

Mengapa hal itu sulit untuk diketahui? Potongan ini harus dipicu dari arahan, katakan your-page-titile = "{{'pageTitle' | translate}}. Arahan ini akan dimasukkan dalam elemen pertama dari setiap halaman. Bagus dan jelas deklaratif.
Martin

oh, dengan edit, saya mengerti apa yang Anda maksud sekarang. yang saya maksudkan adalah bahwa satu liner berpotensi ditempatkan di mana saja, $ rootscope, direktif, dll ...
ton.yeung

0

Jika Anda menggunakan ES6, ini berfungsi dengan baik :).

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

Mungkin Anda bisa mencoba arahan ini.

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

Berikut contohnya:

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

Untuk versi Pembaruan UI-Router 1.0.0+, ( https://ui-router.github.io/guide/ng1/migrate-to-1_0 )

Lihat kode berikut

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);
            }
        }
    }
])

Tambahkan yang berikut ke index.html Anda:

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.