How to dynamically change header based on AngularJS partial view?

后端 未结 22 1968
一向
一向 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:36

    You could define controller at the <html> level.

     <html ng-app="app" ng-controller="titleCtrl">
       <head>
         <title>{{ Page.title() }}</title>
     ...
    

    You create service: Page and modify from controllers.

    myModule.factory('Page', function() {
       var title = 'default';
       return {
         title: function() { return title; },
         setTitle: function(newTitle) { title = newTitle }
       };
    });
    

    Inject Page and Call 'Page.setTitle()' from controllers.

    Here is the concrete example: http://plnkr.co/edit/0e7T6l

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

    Here's a different way to do title changes. Maybe not as scalable as a factory function (which could conceivably handle unlimited pages) but it was easier for me to understand:

    In my index.html I started like this:

        <!DOCTYPE html>
          <html ng-app="app">
            <head>
              <title ng-bind-template="{{title}}">Generic Title That You'll Never See</title>
    

    Then I made a partial called "nav.html":

    <div ng-init="$root.title = 'Welcome'">
        <ul class="unstyled">
            <li><a href="#/login" ng-click="$root.title = 'Login'">Login</a></li>
            <li><a href="#/home" ng-click="$root.title = 'Home'">Home</a></li>
            <li><a href="#/admin" ng-click="$root.title = 'Admin'">Admin</a></li>
            <li><a href="#/critters" ng-click="$root.title = 'Crispy'">Critters</a></li>
        </ul>
    </div>
    

    Then I went back to "index.html" and added the nav.html using ng-include and the ng-view for my partials:

    <body class="ng-cloak" ng-controller="MainCtrl">
        <div ng-include="'partials/nav.html'"></div>
        <div>
            <div ng-view></div>
        </div>
    

    Notice that ng-cloak? It doesn't have anything to do with this answer but it hides the page until it's done loading, a nice touch :) Learn how here: Angularjs - ng-cloak/ng-show elements blink

    Here's the basic module. I put it in a file called "app.js":

    (function () {
        'use strict';
        var app = angular.module("app", ["ngResource"]);
    
        app.config(function ($routeProvider) {
            // configure routes
            $routeProvider.when("/", {
                templateUrl: "partials/home.html",
                controller:"MainCtrl"
            })
                .when("/home", {
                templateUrl: "partials/home.html",
                controller:"MainCtrl"
            })
                .when("/login", {
                templateUrl:"partials/login.html",
                controller:"LoginCtrl"
            })
                .when("/admin", {
                templateUrl:"partials/admin.html",
                controller:"AdminCtrl"
            })
                .when("/critters", {
                templateUrl:"partials/critters.html",
                controller:"CritterCtrl"
            })
                .when("/critters/:id", {
                templateUrl:"partials/critter-detail.html",
                controller:"CritterDetailCtrl"
            })
                .otherwise({redirectTo:"/home"});
        });
    
    }());
    

    If you look toward the end of the module, you'll see that I have a critter-detail page based on :id. It's a partial that is used from the Crispy Critters page. [Corny, I know - maybe it's a site that celebrates all kinds of chicken nuggets ;) Anyway, you could update the title when a user clicks on any link, so in my main Crispy Critters page that leads to the critter-detail page, that's where the $root.title update would go, just like you saw in the nav.html above:

    <a href="#/critters/1" ng-click="$root.title = 'Critter 1'">Critter 1</a>
    <a href="#/critters/2" ng-click="$root.title = 'Critter 2'">Critter 2</a>
    <a href="#/critters/3" ng-click="$root.title = 'Critter 3'">Critter 3</a>
    

    Sorry so windy but I prefer a post that gives enough detail to get it up and running. Note that the example page in the AngularJS docs is out of date and shows a 0.9 version of ng-bind-template. You can see that it's not that much different.

    Afterthought: you know this but it's here for anyone else; at the bottom of the index.html, one must include the app.js with the module:

            <!-- APP -->
            <script type="text/javascript" src="js/app.js"></script>
        </body>
    </html>
    
    0 讨论(0)
  • 2020-11-22 11:39

    jkoreska's solution is perfect if you know the titles before hand, but you may need to set the title based on data you get from a resource etc.

    My solution requires a single service. Since the rootScope is the base of all DOM elements, we don't need to put a controller on the html element like someone mentioned

    Page.js

    app.service('Page', function($rootScope){
        return {
            setTitle: function(title){
                $rootScope.title = title;
            }
        }
    });
    

    index.jade

    doctype html
    html(ng-app='app')
    head
        title(ng-bind='title')
    // ...
    

    All controllers that need to change title

    app.controller('SomeController', function(Page){
        Page.setTitle("Some Title");
    });
    
    0 讨论(0)
  • 2020-11-22 11:42

    While others may have better methods, I was able to use $rootScope in my controllers, as each of my views/templates has a distinct controller. You will need to inject the $rootScope in each controller. While this may not be ideal, it is functioning for me, so I thought I should pass it along. If you inspect the page, it adds the ng-binding to the title tag.

    Example Controller:

    myapp.controller('loginPage', ['$scope', '$rootScope', function ($scope, $rootScope) {
    
    // Dynamic Page Title and Description
    $rootScope.pageTitle = 'Login to Vote';
    $rootScope.pageDescription = 'This page requires you to login';
    }]);
    

    Example Index.html header:

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <meta name="description" content="{{pageDescription}}">
    <meta name="author" content="">
    <link rel="shortcut icon" href="../../assets/ico/favicon.ico">
    <base href="/">
    <title>{{pageTitle}}</title>
    

    You can also set the pageTitle and pageDescription to dynamic values, such as returning data from a REST call:

        $scope.article = restCallSingleArticle.get({ articleID: $routeParams.articleID }, function() {
        // Dynamic Page Title and Description
        $rootScope.pageTitle = $scope.article.articletitle;
        $rootScope.pageDescription = $scope.article.articledescription;
    });
    

    Again, others may have better ideas on how to approach this, but since I am using a pre-rendering, my needs are being met.

    0 讨论(0)
提交回复
热议问题