Wie kann ich den Header basierend auf der AngularJS-Teilansicht dynamisch ändern?

411

Ich verwende ng-view, um AngularJS-Teilansichten einzuschließen, und ich möchte den Seitentitel und die h1-Header-Tags basierend auf der enthaltenen Ansicht aktualisieren. Diese liegen jedoch außerhalb des Bereichs der Teilansichts-Controller, und daher kann ich nicht herausfinden, wie sie an den Datensatz in den Controllern gebunden werden.

Wenn es ASP.NET MVC wäre, könnten Sie @ViewBag verwenden, um dies zu tun, aber ich kenne das Äquivalent in AngularJS nicht. Ich habe nach gemeinsam genutzten Diensten, Ereignissen usw. gesucht, kann es aber immer noch nicht zum Laufen bringen. Jede Möglichkeit, mein Beispiel so zu ändern, dass es funktioniert, wäre sehr dankbar.

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

Mein 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"; }
mikel
quelle
Dieser Kommentar ist vielleicht zu spät, aber ich möchte hinzufügen. cssfacts.com/simple-dynamic-meta-tags-in-angularjs Dies kann nützlich sein, um dynamische Metas festzulegen . Sie ändern lediglich Ihre Metawariable $ rootScope.
Kamuran Sönecek

Antworten:

342

Sie können den Controller auf der <html>Ebene definieren.

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

Sie erstellen einen Service: Pageund ändern ihn über Controller.

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

Injizieren Pageund rufen Sie 'Page.setTitle ()' von Controllern auf.

Hier ist das konkrete Beispiel: http://plnkr.co/edit/0e7T6l

Tosh
quelle
11
ähm ... Ich bin mir nicht sicher, ob es in der AngularJS-Architektur als gut angesehen wird , einen Dienst direkt in den $ -Bereich zu stellen . Vielleicht ist es besser, eine Controller-Funktion in $ scope einzufügen und diese Funktion dann den Dienst abfragen zu lassen.
Superjos
11
Dieses Beispiel war großartig. Ich habe jedoch eine Folge, beim ersten Laden können Sie den Text {{Page.title ()}} im Titel sehen (sehr schnell). Ich glaube nicht, dass du ng-cloak benutzen kannst, da es nicht im Körper ist. Irgendwelche Vorschläge, um dies zu vermeiden?
Arthur Frankel
52
@ArthurFrankel Verwenden Sie einfach ng-bind (zB ng-bind = "Page.title ()")
Pius Uzamere
2
oder wir können den Controller im Titel-Tag angeben, ohne dass ein globaler Controller im HTML-Header erforderlich ist: <title ng-controller = "titleCtrl"> {{Page.title ()}} </ title>
Dmitri Algazin
6
Ich persönlich ziehe es vor, den Titel auf zu setzen, $rootScopeanstatt einen zusätzlichen Controller zu erstellen.
DDA
634

Ich habe gerade eine gute Möglichkeit gefunden, Ihren Seitentitel festzulegen, wenn Sie Routing verwenden:

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

Bearbeiten : Verwenden Sie das ng-bindAttribut anstelle von Locken, {{}}damit sie beim Laden nicht angezeigt werden

jkoreska
quelle
11
Richtig, aber Ihr Beispiel zeigt nicht, wie Sie den Titel in $ routeChangeSuccess ändern können, der durch $ scope-Variablen parametrisiert wird, was das Beispiel von @ tosh mithilfe eines Page-Dienstes tut. Sie können also title = "Blog"aber nicht einstellen title = '{{"Blog post " + post.title}}'.
Eric Drechsel
10
@felix können Sie Titel wie current.titleauch
zugreifen
8
$ rootScope.title = current. $ route.title; ohne doble $$
david.sansay
7
Ich habe gerade meine Angular-Version um mehrere Versionen (1.0.5 auf 1.2.7) aktualisiert und dies hat mich in meinem Code gebrochen. Ich habe current.$routeden alten Code verwendet und er hat funktioniert. Mit dem Upgrade wird die doppelte $ on-Route benötigt. current.$$route
Tyler Forsythe
6
In der Antwort wann kann man sehen '/Product/:id'. Gibt es eine Möglichkeit, den :idWert mit dieser Methode zu haben? Ich habe es versucht, title: function(params){return params.id;}aber es funktioniert nicht ... Vielleicht mit resolve?
Mickaelb91
190

Beachten Sie, dass Sie den Titel auch direkt mit Javascript festlegen können, dh

$window.document.title = someTitleYouCreated;

Dies hat keine Datenbindung, aber es reicht aus, wenn das Einfügen ng-appdes <html>Tags problematisch ist. (Verwenden Sie beispielsweise JSP-Vorlagen, bei denen <head>genau an einer Stelle definiert ist, Sie jedoch mehr als eine App haben.)

broc.seib
quelle
5
Dies war der einzige Weg, um es für mich in Internet Explorer zum Laufen zu bringen, die anderen Methoden funktionierten jedoch in anderen Browsern
Maarten
4
Wie Maarten erwähnte, ist dies der einzige Ansatz, der in ie7 und ie8 funktioniert
rob
33
Erstaunlich, wie die Leute nicht zurücktreten können und sehen, wie einfach dies ohne
Zielfernrohre
7
Nicht zu fassen. Dies war viel einfacher als alle Shenanigans, die andere erwähnten. Vielen Dank!
Leonard Teo
8
Die Verwendung eines einfachen Fensters ist in Ordnung - das wirkt sich direkt auf das DOM aus. '$ window' ist eine eckige Sache, und Sie müssen es injizieren, um es zu verwenden. So oder so wird es funktionieren.
broc.seib
119

Das Deklarieren ng-appdes htmlElements bietet den Stammbereich für das headund body.

Injizieren Sie daher in Ihrem Controller $rootScopeeine Header-Eigenschaft und legen Sie diese fest:

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

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

und auf Ihrer Seite:

<title ng-bind="header"></title>
Andy Hitchman
quelle
8
beste Antwort auf meine Meinung. In diesem Fall ist es nutzlos, einen Controller auf ng-App-Ebene zu haben, wie in der akzeptierten Antwort beschrieben.
Nicolas Janel
1
Ich liebe, wie leicht diese Lösung ist, und es vermeidet die Verwendung von $$ Eigenschaften
tedwards947
Die akzeptierte Antwort fügt unnötige Komplikationen und Risiken hinzu. Diese Version macht es so einfach wie das Festlegen einer Variablen.
Special0ne
3
Wenn Sie fest entschlossen sind, $ rootScope zu verwenden, würde ich dies zumindest für einen Dienst extrahieren, damit Sie $ rootScope nicht in Ihrem Controller haben.
Michael J. Calkins
3
Ich möchte diese Lösung verwenden, bin aber gespannt, welche Vorteile die Verwendung bietet document.title = "App".
Remarsh
43

Das Modul anglejs-viewhead zeigt einen Mechanismus zum Festlegen des Titels pro Ansicht, wobei nur eine benutzerdefinierte Direktive verwendet wird.

Es kann entweder auf ein vorhandenes Ansichtselement angewendet werden, dessen Inhalt bereits der Ansichtstitel ist:

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

... oder es kann als eigenständiges Element verwendet werden. In diesem Fall ist das Element im gerenderten Dokument unsichtbar und wird nur zum Festlegen des Ansichtstitels verwendet:

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

Der Inhalt dieser Direktive wird im Stammbereich als verfügbar gemacht viewTitle, sodass er wie jede andere Variable für das title-Element verwendet werden kann:

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

Es kann auch an jeder anderen Stelle verwendet werden, die den Stammbereich "sehen" kann. Zum Beispiel:

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

Mit dieser Lösung kann der Titel über denselben Mechanismus festgelegt werden, mit dem der Rest der Präsentation gesteuert wird: AngularJS-Vorlagen. Dies vermeidet die Notwendigkeit, Steuerungen mit dieser Präsentationslogik zu überladen. Der Controller muss alle Daten zur Verfügung stellen, die zur Information des Titels verwendet werden. Die Vorlage entscheidet jedoch endgültig, wie sie dargestellt werden soll, und kann Ausdrucksinterpolation und Filter verwenden, um wie gewohnt an Bereichsdaten zu binden.

(Haftungsausschluss: Ich bin der Autor dieses Moduls, verweise hier jedoch nur in der Hoffnung, dass es jemand anderem hilft, dieses Problem zu lösen.)

Martin Atkins
quelle
4
Ich kann nicht glauben, dass diese Lösung nicht mehr positiv bewertet wurde. Die meisten anderen sind wirklich schlechte Designentscheidungen.
Martin Wawrusch
Einverstanden sollte dies die Top-Lösung sein. Ich mag das viel besser, als einen Controller auf Seitenebene zum Festlegen des Titels zu deklarieren. Zu Ihrer Information: Wenn Sie dies mit Angular v1.3.2 und Angular-Route-Segment v1.3.3 verwenden, funktioniert es wie ein Zauber.
Nate Barbettini
Ich unterstütze diese Lösung;)
jkoreska
3
Ich habe hier in meinem Blog ein bisschen mehr über anglejs-viewhead und eine andere verwandte Idee geschrieben: anscheinend.me.uk/angularjs-view-specific-sidebars
Martin Atkins
Wenn dieselbe Ansicht auf oberster und untergeordneter Ebene wiederverwendet wird, kann der Ansichtstitel weiterhin mit einem ng-if verwendet werden, z. B.: <H4 ng-if = "$ state.includes ('some-state')" Ansichtstitel> Details für {{...}} </ h4> <h4 ng-if = "! $ state.includes ('some-state')"> Details für {{...}} </ h4 >
Anre
32

Hier ist eine angepasste Lösung, die für mich funktioniert und keine Injektion von $ rootScope in Controller zum Festlegen ressourcenspezifischer Seitentitel erfordert.

In der Master-Vorlage:

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

In der Routing-Konfiguration:

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

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

Und im Laufblock:

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

Endlich in der Steuerung:

function ProductController($scope) {
    //Load product or use resolve in routing
    $scope.page.setTitle($scope.product.name);
}
Herr Hash
quelle
1
Der in ProductController ($ scope.page.setTitle) festgelegte Titel wird von $ rootScope überschrieben. $ On ('$ routeChangeSuccess'. Das Festlegen eines Standardtitels in $ rootScope. $ On ('$ routeChangeStart' ist in dieser Hinsicht sicherer.
Kristo Aun
@ mr-hash: hier ist eine kleine Anpassung, die ich vorschlage, perfekt für bestehende Winkelprojekte mit vielen Routen, aber ohne Titel. Es wird ein Titel aus dem Namen des Controllers generiert, wenn auf der Route kein Titel definiert ist:$rootScope.page.setTitle(current.$$route.title || current.$$route.controller.replace('Ctrl', ''));
mikhail-t
1
Denken Sie daran, die Ausgabe wie this.title = title.replace('<', '&lt;').replace('>', '&gt;').replace(' & ', ' &amp; ') + ' | Site Name';
folgt
Ich habe einen undefinierten Fehler erhalten und das letzte Bit in $ rootScope.page.title = current geändert. $$ route? aktuell. $$ route.title + '| Site Name ':' Site Name ';
Andy
15

Die Lösung von jkoreska ist perfekt, wenn Sie die Titel vorher kennen, aber Sie müssen den Titel möglicherweise basierend auf Daten festlegen, die Sie von einer Ressource usw. erhalten.

Meine Lösung erfordert einen einzigen Dienst. Da das rootScope die Basis aller DOM-Elemente ist, müssen wir dem HTML-Element keinen Controller hinzufügen, wie dies bereits erwähnt wurde

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

Alle Controller, die den Titel ändern müssen

app.controller('SomeController', function(Page){
    Page.setTitle("Some Title");
});
Deminetix
quelle
kleines Problem, wenn Sie eine Seite aktualisieren, sehen Sie in Ihrem Tab-Namen '{{title}}' und nachdem die Seite gerendert wurde, sehen Sie nur 'Some Title'. Lösung mit Fabrik hat nicht dieses Verhalten
Dmitri Algazin
5
{{title}}Verwenden ng-bind='title'
Sie
1
Stimmen Sie mit @Faradox überein ... using ng-bindverhindert , dass die vorinterpolierte Syntax angezeigt wird , bevor der Titel tatsächlich ausgewertet wird. +100
Seth
11

Eine saubere Methode, mit der Titel oder Meta-Beschreibungen dynamisch festgelegt werden können. In Beispiel verwende ich UI-Router, aber Sie können ngRoute auf die gleiche Weise verwenden.

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>
...
Alex Soroka
quelle
8

Alternativ, wenn Sie einen UI-Router verwenden :

index.html

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

Routing

$stateProvider
  .state('home', {
      url: '/',
      templateUrl: 'views/home.html',
      data: {
        title: 'Welcome Home.'
      }
  }
Nathan Kot
quelle
2
Ich kann dies nicht zum Laufen bringen. Ich habe eine ui-routerAktualisierung der URL und des Inhalts basierend auf meinem Status und erhalte keine Fehler oder Warnungen, aber ich kann scheinbar nicht über einen Teil des Statuskonfigurationsobjekts darauf zugreifen $state.current.[...]. Mit welcher Version ui-routerhaben Sie dies getan?
Meine Bearbeitung der Antwort "Runtime Config" löst das Problem, das ich oben in meinem Kommentar erwähnt habe. :) Ich bin offen für Ideen, ob es einen besseren Weg gibt, dies zu tun.
Dies funktioniert bei mir nicht und 'title' wird in den API-Dokumenten nicht gefunden. Wird dies weiterhin unterstützt?
GraehamF
7

Benutzerdefinierte ereignisbasierte Lösung

Hier ist ein anderer Ansatz, der von den anderen hier nicht erwähnt wurde (zum Zeitpunkt dieses Schreibens).

Sie können benutzerdefinierte Ereignisse wie folgt verwenden:

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

Dieser Ansatz hat den Vorteil, dass keine zusätzlichen Dienste geschrieben und dann in jeden Controller eingefügt werden müssen, der den Titel festlegen muss, und dass er auch nicht (ab) verwendet $rootScope. Sie können damit auch einen dynamischen Titel festlegen (wie im Codebeispiel), der mit benutzerdefinierten Datenattributen für das Konfigurationsobjekt des Routers nicht möglich ist (zumindest soweit ich weiß).

Michael Bromley
quelle
5

In Szenarien, in denen Sie keine ngApp haben, die das titleTag enthält , fügen Sie Controllern, die den Fenstertitel festlegen müssen, einfach einen Dienst hinzu.

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

Arbeitsbeispiel ... http://jsfiddle.net/8m379/1/

JeremyWeir
quelle
5

Wenn Sie keine Kontrolle über das Titelelement haben (wie das asp.net-Webformular), können Sie Folgendes verwenden

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;
        });
    });
Ashish
quelle
4

Einfache und schmutzige Art und Weise mit $rootScope:

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

Wenn Sie in Ihren Controllern über die zum Erstellen des Titels erforderlichen Daten verfügen, gehen Sie wie folgt vor:

$rootScope.title = 'Page X'
user1338062
quelle
4

Keine dieser Antworten schien intuitiv genug zu sein, deshalb habe ich eine kleine Anweisung erstellt, um dies zu tun. Auf diese Weise können Sie den Titel auf der Seite dort deklarieren, wo dies normalerweise der Fall ist, und er kann auch dynamisch sein.

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

Sie müssen natürlich den Modulnamen ändern, um ihn an Ihren anzupassen.

Um es zu verwenden, werfen Sie dies einfach in Ihre Ansicht, ähnlich wie Sie es für ein normales <title>Tag tun würden :

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

Sie können auch nur einfachen Text einfügen, wenn Sie dies nicht benötigen:

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

Alternativ können Sie ein Attribut verwenden, um es IE-freundlicher zu machen:

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

Sie können natürlich jeden gewünschten Text in das Tag einfügen, einschließlich Angular-Code. In diesem Beispiel wird nach dem $scope.titleTextController gesucht, in dem sich das benutzerdefinierte Titel-Tag gerade befindet.

Stellen Sie nur sicher, dass Ihre Seite nicht mehrere Seitentitel-Tags enthält, da sie sich sonst gegenseitig überladen.

Plunker-Beispiel hier http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV . Sie müssen die Zip-Datei herunterladen und lokal ausführen, um die Titeländerung zu sehen.

MikeyB
quelle
Ich habe mir etwas Ähnliches ausgedacht. Bei weitem am intuitivsten zu bedienen und erfordert keinen Controller html. In meiner Direktive füge ich auch eine optionale pageTitlePrefixKonstante ein.
z0r
4

Einfache Lösung für 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);
   });
}]);
the_mishra
quelle
3

Hier ist eine andere Möglichkeit, Titeländerungen vorzunehmen. Vielleicht nicht so skalierbar wie eine Factory-Funktion (die möglicherweise unbegrenzte Seiten verarbeiten kann), aber es war für mich einfacher zu verstehen:

In meiner index.html habe ich so angefangen:

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

Dann habe ich einen Teil namens "nav.html" gemacht:

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

Dann ging ich zurück zu "index.html" und fügte die nav.html mit ng-include und der ng-view für meine Partials hinzu:

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

Beachten Sie, dass ng-Mantel? Es hat nichts mit dieser Antwort zu tun, aber es verbirgt die Seite, bis sie geladen ist , eine nette Geste :) Erfahren Sie hier, wie: Angularjs - ng-cloak / ng-show-Elemente blinken

Hier ist das Grundmodul. Ich habe es in eine Datei namens "app.js" eingefügt:

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

}());

Wenn Sie gegen Ende des Moduls schauen, werden Sie feststellen, dass ich eine Critter-Detail-Seite habe, die auf: id basiert. Es ist ein Teil, der auf der Crispy Critters-Seite verwendet wird. [Blöd, ich weiß - vielleicht ist es eine Seite, auf der alle Arten von Hühnernuggets gefeiert werden;) Wie auch immer, Sie können den Titel aktualisieren, wenn ein Benutzer auf einen beliebigen Link klickt. Dort würde das $ root.title-Update hingehen, genau wie Sie es in der obigen Datei nav.html gesehen haben:

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

Tut mir leid, aber ich bevorzuge einen Beitrag, der genügend Details enthält, um ihn zum Laufen zu bringen. Beachten Sie, dass die Beispielseite in den AngularJS-Dokumenten veraltet ist und eine Version 0.9 der ng-bind-Vorlage zeigt. Sie können sehen, dass es nicht so viel anders ist.

Nachgedacht: Sie wissen das, aber es ist für alle anderen da; Am Ende der index.html muss die Datei app.js im Modul enthalten sein:

        <!-- APP -->
        <script type="text/javascript" src="js/app.js"></script>
    </body>
</html>
Noogrub
quelle
2
Meine Meinung, benutze das nicht. Sie mischen Daten (Informationen) in Ansichten (Präsentation). Später wird es sehr schwierig sein,
Titelquellen
Da der Titel nur aktualisiert wird, wenn tatsächlich auf einen Link geklickt wird , wird der Titel nicht richtig festgelegt, wenn der Benutzer zum ersten Mal auf einer Seite landet oder wenn der Benutzer aktualisiert wird.
Mark Amery
3

Als ich das lösen musste, konnte ich das nicht ng-appauf dem htmlTag der Seite platzieren , also habe ich es mit einem Service gelöst:

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

});
Tom Söderlund
quelle
2

Benutzerdefinierte ereignisbasierte Lösung, inspiriert von Michael Bromley

Ich konnte es nicht mit $ scope zum Laufen bringen, also habe ich es mit rootScope versucht, vielleicht etwas schmutziger ... (insbesondere, wenn Sie eine Aktualisierung auf der Seite vornehmen, die das Ereignis nicht registriert)

Aber ich mag die Idee wirklich, wie die Dinge lose miteinander verbunden sind.

Ich benutze anglejs 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>

Es funktioniert für mich :)


Thomas
quelle
1

Während andere möglicherweise bessere Methoden haben, konnte ich $ rootScope in meinen Controllern verwenden, da jede meiner Ansichten / Vorlagen einen eigenen Controller hat. Sie müssen das $ rootScope in jeden Controller injizieren. Das ist vielleicht nicht ideal, aber es funktioniert für mich, also dachte ich, ich sollte es weitergeben. Wenn Sie die Seite überprüfen, wird die ng-Bindung zum Titel-Tag hinzugefügt.

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

Beispiel für einen 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>

Sie können pageTitle und pageDescription auch auf dynamische Werte setzen, z. B. die Rückgabe von Daten aus einem REST-Aufruf:

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

Auch hier haben andere vielleicht bessere Ideen, wie sie dies angehen sollen, aber da ich ein Pre-Rendering verwende, werden meine Anforderungen erfüllt.

Kode
quelle
0

Vielen Dank an tosh shimayama für seine Lösung.
Ich dachte, es wäre nicht so sauber, einen Dienst direkt in den Dienst zu stellen $scope. Deshalb hier meine geringfügige Variation: http://plnkr.co/edit/QJbuZZnZEDOBcYrJXWWs

Der Controller (der mir in der ursprünglichen Antwort etwas zu dumm erschien) erstellt ein ActionBar-Objekt, das in $ scope gestopft ist.
Das Objekt ist für die tatsächliche Abfrage des Dienstes verantwortlich. Es ist auch versteckt aus dem $ Rahmen der Aufruf der Vorlage URL zu setzen, die stattdessen an andere Steuerungen verfügbar ist , um die URL zu setzen.

Superjos
quelle
0

Herr Hash hatte bisher die beste Antwort, aber die folgende Lösung macht sie (für mich) ideal, indem sie die folgenden Vorteile hinzufügt:

  • Fügt keine Uhren hinzu, was die Dinge verlangsamen kann
  • Automatisiert tatsächlich, was ich in der Steuerung noch getan haben könnte
  • Gibt mir immer noch Zugriff vom Controller, wenn ich es noch will.
  • Keine zusätzliche Injektion

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

Im Laufblock:

.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
])
Kim Miller
quelle
-4

Die bessere und dynamischere Lösung, die ich gefunden habe, besteht darin, $ watch zu verwenden, um die Variablenänderungen zu verfolgen und dann den Titel zu aktualisieren.

Geolyth
quelle