Comment changer dynamiquement l'en-tête basé sur la vue partielle AngularJS?


411

J'utilise ng-view pour inclure les vues partielles AngularJS et je souhaite mettre à jour le titre de la page et les balises d'en-tête h1 en fonction de la vue incluse. Cependant, ceux-ci sont hors de portée des contrôleurs de vue partielle, et je ne peux donc pas comprendre comment les lier à l'ensemble de données dans les contrôleurs.

Si c'était ASP.NET MVC, vous pourriez utiliser @ViewBag pour cela, mais je ne connais pas l'équivalent dans AngularJS. J'ai cherché des services partagés, des événements, etc., mais je n'arrive toujours pas à le faire fonctionner. Toute façon de modifier mon exemple afin qu'il fonctionne serait très appréciée.

Mon HTML:

<html data-ng-app="myModule">
<head>
<!-- include js files -->
<title><!-- should changed when ng-view changes --></title>
</head>
<body>
<h1><!-- should changed when ng-view changes --></h1>

<div data-ng-view></div>

</body>
</html>

Mon JavaScript:

var myModule = angular.module('myModule', []);
myModule.config(['$routeProvider', function($routeProvider) {
    $routeProvider.
        when('/test1', {templateUrl: 'test1.html', controller: Test1Ctrl}).
        when('/test2', {templateUrl: 'test2.html', controller: Test2Ctrl}).
        otherwise({redirectTo: '/test1'});
}]);

function Test1Ctrl($scope, $http) { $scope.header = "Test 1"; 
                                  /* ^ how can I put this in title and h1 */ }
function Test2Ctrl($scope, $http) { $scope.header = "Test 2"; }

Ce commentaire est peut-être en retard mais je veux ajouter. cssfacts.com/simple-dynamic-meta-tags-in-angularjs Cela peut être utile pour définir des métas dynamiques. Vous allez juste changer votre méta variable $ rootScope.
Kamuran Sönecek

Réponses:


342

Vous pouvez définir le contrôleur au <html>niveau.

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

Vous créez le service: Pageet modifiez à partir des contrôleurs.

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

Injectez Pageet appelez «Page.setTitle ()» à partir des contrôleurs.

Voici l'exemple concret: http://plnkr.co/edit/0e7T6l


11
euhmm ... Je ne sais pas si placer un service directement dans la portée $ est considéré comme agréable dans l'architecture AngularJS. Il serait peut-être préférable de mettre dans $ scope une fonction Controller, puis de laisser cette fonction interroger le service.
superjos

11
Cet exemple était formidable. J'ai un suivi cependant, lors du chargement initial, vous pouvez voir le texte {{Page.title ()}} dans le titre (très rapidement). Je ne pense pas que vous puissiez utiliser ng-cloak car il n'est pas dans le corps. Des suggestions pour éviter cela?
Arthur Frankel

52
@ArthurFrankel Il suffit d'utiliser ng-bind (par exemple ng-bind = "Page.title ()")
Pius Uzamere

2
ou nous pouvons spécifier le contrôleur dans la balise title, pas besoin de contrôleur global sur l'en-tête html: <title ng-controller = "titleCtrl"> {{Page.title ()}} </title>
Dmitri Algazin

6
Personnellement, je préfère définir le titre au $rootScopelieu de créer un contrôleur supplémentaire.
DDA

634

Je viens de découvrir une belle façon de définir le titre de votre page si vous utilisez le routage:

JavaScript:

var myApp = angular.module('myApp', ['ngResource'])

myApp.config(
    ['$routeProvider', function($routeProvider) {
        $routeProvider.when('/', {
            title: 'Home',
            templateUrl: '/Assets/Views/Home.html',
            controller: 'HomeController'
        });
        $routeProvider.when('/Product/:id', {
            title: 'Product',
            templateUrl: '/Assets/Views/Product.html',
            controller: 'ProductController'
        });
    }]);

myApp.run(['$rootScope', function($rootScope) {
    $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
        $rootScope.title = current.$$route.title;
    });
}]);

HTML:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <title ng-bind="'myApp &mdash; ' + title">myApp</title>
...

Modifier : utiliser l' ng-bindattribut au lieu de curlies {{}}pour qu'ils ne s'affichent pas à la charge


11
à droite, mais votre exemple ne montre pas comment changer le titre sur $ routeChangeSuccess paramétré par les variables $ scope, ce que fait l'exemple de @ tosh utilisant un service Page. Vous pouvez donc définir title = "Blog"mais pas title = '{{"Blog post " + post.title}}'.
Eric Drechsel

10
@felix vous pouvez accéder au titre comme current.titleaussi
Eldelshell

8
$ rootScope.title = current. $ route.title; sans doble $$
david.sansay

7
Je viens de mettre à jour ma version Angular en plusieurs versions (1.0.5 à 1.2.7) et cela m'a brisé dans mon code. J'utilisais current.$routedans l'ancien code et cela fonctionnait. Avec la mise à niveau, le double $ sur l'itinéraire est nécessaire. current.$$route
Tyler Forsythe

6
Dans la réponse quand peut voir '/Product/:id'. Existe-t-il un moyen d'avoir la :idvaleur avec cette méthode? J'ai essayé title: function(params){return params.id;}mais ça ne marche pas ... Peut-être en utilisant resolve?
mickaelb91

190

Notez que vous pouvez également définir le titre directement avec javascript, c'est-à-dire,

$window.document.title = someTitleYouCreated;

Cela n'a pas de liaison de données, mais cela suffit lorsque la mise ng-appen place de la <html>balise est problématique. (Par exemple, en utilisant des modèles JSP où <head>est défini exactement à un endroit, mais vous avez plus d'une application.)


5
C'était le seul moyen de le faire fonctionner sur Internet Explorer pour moi, les autres méthodes fonctionnaient cependant sur d'autres navigateurs
Maarten

4
Comme Maarten l'a mentionné, c'est la seule approche qui fonctionne dans ie7 et ie8
rob

33
Incroyable comment les gens ne peuvent pas prendre du recul et voir avec quelle facilité cette chose peut être faite sans scopes et usines
redben

7
Incroyable. C'était beaucoup plus simple que tous les manigances que d'autres mentionnaient. Merci!
Leonard Teo

8
Utiliser une simple "fenêtre" est très bien - cela agit directement sur le DOM. '$ window' est une chose angulaire, et vous devez l'injecter pour l'utiliser. Dans les deux cas, cela fonctionnera.
broc.seib

119

La déclaration ng-appsur l' htmlélément fournit une portée racine à la fois pour headet body.

Par conséquent, dans votre contrôleur, injectez $rootScopeet définissez une propriété d'en-tête:

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

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

et dans votre page:

<title ng-bind="header"></title>

8
meilleure réponse à mon avis. Avoir un contrôleur au niveau ng-app comme décrit dans la réponse acceptée est inutile dans ce cas.
Nicolas Janel

1
j'adore la légèreté de cette solution et elle évite d'utiliser les propriétés $$
tedwards947

La réponse acceptée ajoute des complications et des risques inutiles. Cette version le rend aussi simple que de définir une variable.
special0ne

3
Si vous êtes prêt à utiliser $ rootScope, j'extrais au moins cela vers un service afin que vous n'ayez pas $ rootScope dans votre contrôleur.
Michael J.Calkins

3
Je veux utiliser cette solution mais je suis curieux de savoir quels sont les avantages de son utilisation document.title = "App";
remarsh

43

Le module angularjs-viewhead montre un mécanisme pour définir le titre par vue en utilisant uniquement une directive personnalisée.

Il peut être appliqué à un élément de vue existant dont le contenu est déjà le titre de la vue:

<h2 view-title>About This Site</h2>

... ou il peut être utilisé comme élément autonome, auquel cas l'élément sera invisible dans le document rendu et ne sera utilisé que pour définir le titre de la vue:

<view-title>About This Site</view-title>

Le contenu de cette directive est rendu disponible dans la portée racine en tant que viewTitle, il peut donc être utilisé sur l'élément title comme n'importe quelle autre variable:

<title ng-bind-template="{{viewTitle}} - My Site">My Site</title>

Il peut également être utilisé à tout autre endroit qui peut "voir" la portée racine. Par exemple:

<h1>{{viewTitle}}</h1>

Cette solution permet de définir le titre via le même mécanisme que celui utilisé pour contrôler le reste de la présentation: les modèles AngularJS. Cela évite d'avoir à encombrer les contrôleurs avec cette logique de présentation. Le responsable du traitement doit mettre à disposition toutes les données qui seront utilisées pour informer le titre, mais le modèle prend la décision finale sur la façon de le présenter, et peut utiliser l'interpolation d'expression et des filtres pour se lier aux données de portée comme d'habitude.

(Avertissement: je suis l'auteur de ce module, mais je ne le référence ici que dans l'espoir qu'il aidera quelqu'un d'autre à résoudre ce problème.)


4
Je ne peux pas croire que cette solution n'ait pas été plus appréciée. La plupart des autres sont de très mauvais choix de conception.
Martin Wawrusch

D'accord, cela devrait être la meilleure solution. J'aime beaucoup mieux que de déclarer un contrôleur au niveau de la page pour définir le titre. Pour info: l'utiliser avec Angular v1.3.2 et angular-route-segment v1.3.3 et cela fonctionne comme un charme.
Nate Barbettini


3
J'ai écrit un peu plus sur angularjs-viewhead et une autre idée connexe ici sur mon blog: apparemment.me.uk/angularjs-view-specific-sidebars
Martin Atkins

Si vous réutilisez la même vue au niveau supérieur et au niveau inférieur, on peut toujours utiliser view-title avec un ng-if, par exemple: <h4 ng-if = "$ state.includes ('some-state')" view-title> Détails pour {{...}} </h4> <h4 ng-if = "! $ state.includes ('some-state')"> Détails pour {{...}} </ h4 >
anre

32

Voici une solution adaptée qui fonctionne pour moi qui ne nécessite pas d'injection de $ rootScope dans les contrôleurs pour définir les titres de page spécifiques aux ressources.

Dans le modèle maître:

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

Dans la configuration de routage:

$routeProvider.when('/products', {
    title: 'Products',
    templateUrl: '/partials/products.list.html',
    controller: 'ProductsController'
});

$routeProvider.when('/products/:id', {
    templateUrl: '/partials/products.detail.html',
    controller: 'ProductController'
});

Et dans le bloc d'exécution:

myApp.run(['$rootScope', function($rootScope) {
    $rootScope.page = {
        setTitle: function(title) {
            this.title = title + ' | Site Name';
        }
    }

    $rootScope.$on('$routeChangeSuccess', function(event, current, previous) {
        $rootScope.page.setTitle(current.$$route.title || 'Default Title');
    });
}]);

Enfin dans le contrôleur:

function ProductController($scope) {
    //Load product or use resolve in routing
    $scope.page.setTitle($scope.product.name);
}

1
Le titre défini dans ProductController ($ scope.page.setTitle) est remplacé par $ rootScope. $ On ('$ routeChangeSuccess'. La définition d'un titre par défaut dans $ rootScope. $ On ('$ routeChangeStart' est plus sûre à cet égard.
Kristo Aun

@ mr-hash: voici un petit ajustement que je propose, parfait pour les projets angulaires existants avec de nombreux itinéraires, mais sans titres. Il générera un titre à partir du nom du contrôleur, si aucun titre n'est défini sur l'itinéraire:$rootScope.page.setTitle(current.$$route.title || current.$$route.controller.replace('Ctrl', ''));
mikhail-t

1
n'oubliez pas de désinfecter la sortie comme ceci:this.title = title.replace('<', '&lt;').replace('>', '&gt;').replace(' & ', ' &amp; ') + ' | Site Name';
Henrik Stenbæk

J'ai eu une erreur non définie, j'ai donc changé le dernier bit en: $ rootScope.page.title = current. $$ route? actuel. $$ route.title + '| Nom du site ':' Nom du site ';
Andy

15

La solution de jkoreska est parfaite si vous connaissez les titres à l'avance, mais vous devrez peut-être définir le titre en fonction des données que vous obtenez d'une ressource, etc.

Ma solution nécessite un seul service. Puisque le rootScope est la base de tous les éléments DOM, nous n'avons pas besoin de mettre un contrôleur sur l'élément html comme quelqu'un mentionné

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')
// ...

Tous les contrôleurs qui doivent changer de titre

app.controller('SomeController', function(Page){
    Page.setTitle("Some Title");
});

petit problème, lorsque vous actualisez une page, dans votre nom d'onglet vous voyez '{{title}}' et après que la page a été rendue, vous voyez 'Some Title' seulement. solution avec l'usine n'a pas ce comportement
Dmitri Algazin

5
{{title}}utilisez plutôtng-bind='title'
Faradox

1
D'accord avec @Faradox ... l'utilisation ng-bindempêche la syntaxe pré-interpolée de s'afficher avant que le titre ne soit réellement évalué. +100
Seth

11

Une manière propre qui permet de définir dynamiquement le titre ou la méta description. Par exemple, j'utilise ui-router mais vous pouvez utiliser ngRoute de la même manière.

var myApp = angular.module('myApp', ['ui.router'])

myApp.config(
    ['$stateProvider', function($stateProvider) {
        $stateProvider.state('product', {
            url: '/product/{id}',
            templateUrl: 'views/product.html',
            resolve: {
                meta: ['$rootScope', '$stateParams', function ($rootScope, $stateParams) {
                    var title = "Product " + $stateParams.id,
                        description = "Product " + $stateParams.id;
                    $rootScope.meta = {title: title, description: description};
                }]

                // Or using server side title and description
                meta: ['$rootScope', '$stateParams', '$http', function ($rootScope, $stateParams, $http) {
                    return $http({method: 'GET', url: 'api/product/ + $stateParams.id'})
                        .then (function (product) {
                            $rootScope.meta = {title: product.title, description: product.description};
                        });
                }]

            }
            controller: 'ProductController'
        });
    }]);

HTML:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <title ng-bind="meta.title + ' | My App'">myApp</title>
...

8

Alternativement, si vous utilisez ui-router :

index.html

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <title ng-bind="$state.current.data.title || 'App'">App</title>

Acheminement

$stateProvider
  .state('home', {
      url: '/',
      templateUrl: 'views/home.html',
      data: {
        title: 'Welcome Home.'
      }
  }

2
Je n'arrive pas à faire fonctionner cela. J'ai mis à ui-routerjour l'URL et le contenu en fonction de mon état et je ne reçois aucune erreur ni avertissement, mais je n'arrive pas à accéder à aucune partie de l'objet de configuration d'état via $state.current.[...]. Quelle version ui-routeravez-vous utilisée pour ce faire?

Mon "Runtime Config" modifier la réponse résout le problème que j'ai mentionné dans mon commentaire ci-dessus. :) Je suis ouvert aux idées s'il y a une meilleure façon de le faire.

cela ne fonctionne pas pour moi et «title» ne se trouve pas dans les documents de l'API - est-ce toujours pris en charge?
GraehamF

7

Solution personnalisée basée sur les événements

Voici une autre approche qui n'a pas été mentionnée par les autres ici (au moment d'écrire ces lignes).

Vous pouvez utiliser des événements personnalisés comme ceci:

// your index.html template
<html ng-app="app">
<head>
<title ng-bind="pageTitle">My App</title>

// your main app controller that is declared on the <html> element
app.controller('AppController', function($scope) {
    $scope.$on('title-updated', function(newTitle) {
        $scope.pageTitle = newTitle;
    });
});

// some controller somewhere deep inside your app
mySubmodule.controller('SomeController', function($scope, dynamicService) {
    $scope.$emit('title-updated', dynamicService.title);
});

Cette approche a l'avantage de ne pas nécessiter l'écriture de services supplémentaires, puis d'être injectée dans chaque contrôleur qui doit définir le titre, et n'utilise pas (ab) le $rootScope. Il vous permet également de définir un titre dynamique (comme dans l'exemple de code), ce qui n'est pas possible en utilisant des attributs de données personnalisés sur l'objet de configuration du routeur (pour autant que je sache au moins).


5

Pour les scénarios où vous n'avez pas de ngApp contenant la titlebalise, injectez simplement un service aux contrôleurs qui doivent définir le titre de la fenêtre.

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

Exemple de travail ... http://jsfiddle.net/8m379/1/


5

Si vous ne contrôlez pas l'élément de titre (comme le formulaire Web asp.net), voici quelque chose que vous pouvez utiliser

var app = angular.module("myApp")
    .config(function ($routeProvider) {
                $routeProvider.when('/', {
                                            title: 'My Page Title',
                                            controller: 'MyController',
                                            templateUrl: 'view/myView.html'
                                        })
                            .otherwise({ redirectTo: '/' });
    })
    .run(function ($rootScope) {
        $rootScope.$on("$routeChangeSuccess", function (event, currentRoute, previousRoute) {
            document.title = currentRoute.title;
        });
    });

4

Manière simple et sale en utilisant $rootScope:

<html ng-app="project">
<head>
<title ng-bind="title">Placeholder title</title>

Dans vos contrôleurs, lorsque vous avez les données nécessaires pour créer le titre, faites:

$rootScope.title = 'Page X'

4

Aucune de ces réponses ne semblait assez intuitive, j'ai donc créé une petite directive pour ce faire. De cette façon, vous pouvez déclarer le titre dans la page, où on le ferait normalement, et lui permettre d'être dynamique également.

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

Vous devrez bien sûr changer le nom du module pour qu'il corresponde au vôtre.

Pour l'utiliser, jetez simplement ceci dans votre vue, tout comme vous le feriez pour une <title>balise régulière :

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

Vous pouvez également simplement inclure du texte brut si vous n'en avez pas besoin par dynamique:

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

Alternativement, vous pouvez utiliser un attribut, pour le rendre plus convivial pour IE:

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

Vous pouvez mettre le texte que vous voulez dans la balise bien sûr, y compris le code angulaire. Dans cet exemple, il recherchera$scope.titleText le contrôleur dans lequel se trouve actuellement la balise de titre personnalisé.

Assurez-vous simplement que vous n'avez pas plusieurs balises de titre de page sur votre page, sinon elles s'encombreront.

Exemple de Plunker ici http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV . Vous devrez télécharger le zip et l'exécuter localement afin de voir le changement de titre.


J'ai trouvé quelque chose de similaire. De loin le plus intuitif à utiliser, et ne nécessite pas de mettre un contrôleur html. Dans ma directive, j'injecte également une pageTitlePrefixconstante facultative .
z0r

4

Solution simpliste pour angular-ui-router:

HTML:

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

App.js> bloc myApp.config

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

3

Voici une autre façon de modifier le titre. Peut-être pas aussi évolutif qu'une fonction d'usine (qui pourrait en théorie gérer un nombre illimité de pages) mais il était plus facile pour moi de comprendre:

Dans mon index.html j'ai commencé comme ceci:

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

Ensuite, j'ai fait un partiel appelé "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>

Ensuite, je suis retourné à "index.html" et j'ai ajouté le nav.html en utilisant ng-include et la vue ng pour mes partiels:

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

Remarquez ce ng-manteau? Cela n'a rien à voir avec cette réponse, mais elle masque la page jusqu'à ce qu'elle soit terminée, une belle touche :) Apprenez comment ici: Angularjs - les éléments ng-cloak / ng-show clignotent

Voici le module de base. Je l'ai mis dans un fichier appelé "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"});
    });

}());

Si vous regardez vers la fin du module, vous verrez que j'ai une page de détail de créature basée sur: id. C'est un partiel qui est utilisé à partir de la page Crispy Critters. [Corny, je sais - c'est peut-être un site qui célèbre toutes sortes de pépites de poulet;) Quoi qu'il en soit, vous pouvez mettre à jour le titre lorsqu'un utilisateur clique sur n'importe quel lien, donc dans ma page principale de Crispy Critters qui mène à la page de détail de la créature, c'est là que la mise à jour $ root.title irait, comme vous l'avez vu dans le nav.html ci-dessus:

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

Désolé si venteux mais je préfère un article qui donne suffisamment de détails pour le mettre en route. Notez que la page d'exemple dans les documents AngularJS est obsolète et montre une version 0.9 de ng-bind-template. Vous pouvez voir que ce n'est pas si différent.

Après coup: vous le savez, mais il est là pour quelqu'un d'autre; en bas de l'index.html, il faut inclure app.js avec le module:

        <!-- APP -->
        <script type="text/javascript" src="js/app.js"></script>
    </body>
</html>

2
À mon avis, ne l'utilisez pas. Vous mélangez des données (informations) dans des vues (présentation). Plus tard, il sera très difficile de trouver des sources de titres éparpillées partout dans vos liens HTML qui peuvent être présents à divers endroits de la vue ..
amit bakle

Étant donné que le titre n'est mis à jour qu'en cliquant sur un lien , cela ne définit pas correctement le titre lorsque l'utilisateur atterrit pour la première fois sur une page ou lorsque l'utilisateur se rafraîchit.
Mark Amery

3

Quand j'ai dû résoudre ce problème, je ne pouvais pas placer le tag ng-appsur la page html, alors je l'ai résolu avec un service:

angular.module('myapp.common').factory('pageInfo', function ($document) {

    // Public API
    return {
        // Set page <title> tag. Both parameters are optional.
        setTitle: function (title, hideTextLogo) {
            var defaultTitle = "My App - and my app's cool tagline";
            var newTitle = (title ? title : defaultTitle) + (hideTextLogo ? '' : ' - My App')
            $document[0].title = newTitle;
        }
    };

});

2

Solution événementielle personnalisée inspirée de Michael Bromley

Je n'ai pas pu le faire fonctionner avec $ scope, j'ai donc essayé avec rootScope, peut-être un peu plus sale ... (surtout si vous faites un rafraîchissement sur la page qui n'enregistre pas l'événement)

Mais j'aime vraiment l'idée de la façon dont les choses sont lâchement couplées.

J'utilise 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>

Ça marche pour moi :)



1

Alors que d'autres peuvent avoir de meilleures méthodes, j'ai pu utiliser $ rootScope dans mes contrôleurs, car chacune de mes vues / modèles a un contrôleur distinct. Vous devrez injecter $ rootScope dans chaque contrôleur. Bien que cela ne soit pas idéal, cela fonctionne pour moi, alors j'ai pensé que je devais le transmettre. Si vous inspectez la page, il ajoute la liaison ng à la balise de titre.

Exemple de contrôleur:

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

Exemple d'en-tête Index.html:

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

Vous pouvez également définir le pageTitle et la pageDescription sur des valeurs dynamiques, telles que le renvoi de données à partir d'un appel REST:

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

Encore une fois, d'autres peuvent avoir de meilleures idées sur la façon d'aborder cela, mais comme j'utilise un pré-rendu, mes besoins sont satisfaits.


0

Merci à tosh shimayama pour sa solution.
Je pensais que ce n'était pas si propre de mettre un service directement dans le $scope, alors voici ma légère variation à ce sujet: http://plnkr.co/edit/QJbuZZnZEDOBcYrJXWWs

Le contrôleur (qui dans la réponse d'origine me semblait un peu trop stupide) crée un objet ActionBar, et celui-ci est inséré dans $ scope.
L'objet est chargé d'interroger réellement le service. Il masque également la portée $ l'appel pour définir l'URL du modèle, qui est à la place disponible pour d'autres contrôleurs pour définir l'URL.


0

M. Hash a eu la meilleure réponse jusqu'à présent, mais la solution ci-dessous la rend idéale (pour moi) en ajoutant les avantages suivants:

  • N'ajoute aucune montre, ce qui peut ralentir les choses
  • Automatise en fait ce que j'aurais pu faire dans le contrôleur, mais
  • Me donne toujours accès à partir du contrôleur si je le veux toujours.
  • Pas d'injection supplémentaire

Dans le routeur:

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

Dans le bloc d'exécution:

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

-4

La solution meilleure et dynamique que j'ai trouvée consiste à utiliser $ watch pour suivre les modifications des variables, puis à mettre à jour le titre.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.