How to dynamically change header based on AngularJS partial view?

后端 未结 22 1966
一向
一向 2020-11-22 10:53

I am using ng-view to include AngularJS partial views, and I want to update the page title and h1 header tags based on the included view. These are out of scope of the parti

相关标签:
22条回答
  • 2020-11-22 11:22

    For scenarios that you don't have an ngApp that contains the title tag, just inject a service to controllers that need to set the window title.

    var app = angular.module('MyApp', []);
    
    app.controller('MyController', function($scope, SomeService, Title){
        var serviceData = SomeService.get();
        Title.set("Title of the page about " + serviceData.firstname);
    });
    
    app.factory('SomeService', function ($window) {
        return {
            get: function(){
                return { firstname : "Joe" };
            }
        };
    });
    
    app.factory('Title', function ($window) {
        return {
            set: function(val){
                $window.document.title = val;
            }
        };
    });
    

    Working example... http://jsfiddle.net/8m379/1/

    0 讨论(0)
  • 2020-11-22 11:22

    None of these answers seemed intuitive enough, so I created a small directive to do this. This way allows you to declare the title in the page, where one would normally do it, and allows it to be dynamic as well.

    angular.module('myModule').directive('pageTitle', function() {
        return {
            restrict: 'EA',
            link: function($scope, $element) {
                var el = $element[0];
                el.hidden = true; // So the text not actually visible on the page
    
                var text = function() {
                    return el.innerHTML;
                };
                var setTitle = function(title) {
                    document.title = title;
                };
                $scope.$watch(text, setTitle);
            }
        };
    });
    

    You'll need to of course change the module name to match yours.

    To use it, just throw this in your view, much as you would do for a regular <title> tag:

    <page-title>{{titleText}}</page-title>
    

    You can also just include plain text if you don't need it to by dynamic:

    <page-title>Subpage X</page-title>
    

    Alternatively, you can use an attribute, to make it more IE-friendly:

    <div page-title>Title: {{titleText}}</div>
    

    You can put whatever text you want in the tag of course, including Angular code. In this example, it will look for $scope.titleText in whichever controller the custom-title tag is currently in.

    Just make sure you don't have multiple page-title tags on your page, or they'll clobber each other.

    Plunker example here http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV. You'll have to download the zip and run it locally in order to see the title change.

    0 讨论(0)
  • 2020-11-22 11:22

    Simplistic solution for angular-ui-router :

    HTML :

    <html ng-app="myApp">
      <head>
         <title ng-bind="title"></title>
         .....
         .....  
      </head>
    </html>
    

    App.js > myApp.config block

    $stateProvider
        .state("home", {
            title: "My app title this will be binded in html title",
            url: "/home",
            templateUrl: "/home.html",
            controller: "homeCtrl"
        })
    

    App.js>myApp.run

    myApp.run(['$rootScope','$state', function($rootScope,$state) {
       $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
        $rootScope.title = $state.current.title;
        console.log($state);
       });
    }]);
    
    0 讨论(0)
  • 2020-11-22 11:23

    Mr Hash had the best answer so far, but the solution below makes it ideal (for me) by adding the following benefits:

    • Adds no watches, which can slow things down
    • Actually automates what I might have done in the controller, yet
    • Still gives me access from the controller if I still want it.
    • No extra injecting

    In the router:

      .when '/proposals',
        title: 'Proposals',
        templateUrl: 'proposals/index.html'
        controller: 'ProposalListCtrl'
        resolve:
          pageTitle: [ '$rootScope', '$route', ($rootScope, $route) ->
            $rootScope.page.setTitle($route.current.params.filter + ' ' + $route.current.title)
          ]
    

    In the run block:

    .run(['$rootScope', ($rootScope) ->
      $rootScope.page =
        prefix: ''
        body: ' | ' + 'Online Group Consensus Tool'
        brand: ' | ' + 'Spokenvote'
        setTitle: (prefix, body) ->
          @prefix = if prefix then ' ' + prefix.charAt(0).toUpperCase() + prefix.substring(1) else @prifix
          @body = if body then ' | ' + body.charAt(0).toUpperCase() + body.substring(1) else @body
          @title = @prefix + @body + @brand
    ])
    
    0 讨论(0)
  • 2020-11-22 11:24

    Custom Event Based solution inspired from Michael Bromley

    I wasn't able to make it work with $scope, so I tried with rootScope, maybe a bit more dirty... (especially if you make a refresh on the page that do not register the event)

    But I really like the idea of how things are loosely coupled.

    I'm using angularjs 1.6.9

    index.run.js

    angular
    .module('myApp')
    .run(runBlock);
    
    function runBlock($rootScope, ...)
    {
      $rootScope.$on('title-updated', function(event, newTitle) {
        $rootScope.pageTitle = 'MyApp | ' + newTitle;
      });
    }
    

    anyController.controller.js

    angular
    .module('myApp')
    .controller('MainController', MainController);
    
    function MainController($rootScope, ...)
    {
      //simple way :
      $rootScope.$emit('title-updated', 'my new title');
    
      // with data from rest call
      TroncQueteurResource.get({id:tronc_queteur_id}).$promise.then(function(tronc_queteur){
      vm.current.tronc_queteur = tronc_queteur;
    
      $rootScope.$emit('title-updated', moment().format('YYYY-MM-DD') + ' - Tronc '+vm.current.tronc_queteur.id+' - ' +
                                                 vm.current.tronc_queteur.point_quete.name + ' - '+
                                                 vm.current.tronc_queteur.queteur.first_name +' '+vm.current.tronc_queteur.queteur.last_name
      );
     });
    
     ....}
    

    index.html

    <!doctype html>
    <html ng-app="myApp">
      <head>
        <meta charset="utf-8">
        <title ng-bind="pageTitle">My App</title>
    

    It's working for me :)


    0 讨论(0)
  • 2020-11-22 11:26

    Declaring ng-app on the html element provides root scope for both the head and body.

    Therefore in your controller inject $rootScope and set a header property on this:

    function Test1Ctrl($rootScope, $scope, $http) { $rootScope.header = "Test 1"; }
    
    function Test2Ctrl($rootScope, $scope, $http) { $rootScope.header = "Test 2"; }
    

    and in your page:

    <title ng-bind="header"></title>
    
    0 讨论(0)
提交回复
热议问题