Jak dynamicznie zmieniać nagłówek na podstawie częściowego widoku AngularJS?

411

Używam ng-view, aby uwzględnić widoki częściowe AngularJS i chcę zaktualizować tytuł strony i tagi nagłówka h1 na podstawie dołączonego widoku. Są one jednak poza zakresem kontrolerów widoku częściowego, więc nie mogę wymyślić, jak powiązać je z zestawem danych w kontrolerach.

Gdyby to był ASP.NET MVC, możesz użyć @ViewBag, aby to zrobić, ale nie znam odpowiednika w AngularJS. Szukałem usług wspólnych, wydarzeń itp., Ale nadal nie mogę ich uruchomić. Jakikolwiek sposób zmodyfikowania mojego przykładu, aby działał, byłby mile widziany.

Mój 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>

Mój 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
źródło
Ten komentarz może późno, ale chcę dodać. cssfacts.com/simple-dynamic-meta-tags-in-angularjs Może to być przydatne do ustawiania dynamicznych metas. Po prostu zmienisz swoją meta zmienną $ rootScope.
Kamuran Sönecek

Odpowiedzi:

342

Możesz zdefiniować kontroler na <html>poziomie.

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

Tworzysz usługę: Pagei modyfikujesz z kontrolerów.

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

Inject Pagei nazywają 'Page.setTitle ()' z kontrolerami.

Oto konkretny przykład: http://plnkr.co/edit/0e7T6l

Bzdury
źródło
11
uhmm ... Nie jestem pewien, czy umieszczenie usługi bezpośrednio w zakresie $ jest uważane za dobre w architekturze AngularJS. Może lepiej byłoby umieścić w $ scope funkcję kontrolera, a następnie pozwolić tej funkcji na zapytanie usługi.
superjos,
11
Ten przykład był wspaniały. Mam jednak jedną kontynuację: przy pierwszym załadowaniu możesz zobaczyć tekst {{Page.title ()}} w tytule (bardzo szybko). Nie sądzę, żebyś mógł używać peleryny ng, ponieważ nie ma jej w ciele. Wszelkie sugestie, aby tego uniknąć?
Arthur Frankel
52
@ArthurFrankel Wystarczy użyć ng-bind (np. Ng-bind = "Page.title ()")
Pius Uzamere
2
lub możemy podać kontroler w tytule, nie ma potrzeby globalnego kontrolera w nagłówku HTML: <title ng-controller = "titleCtrl"> {{Page.title ()}} </title>
Dmitri Algazin
6
Osobiście wolę ustawić tytuł $rootScopezamiast tworzyć dodatkowy kontroler.
DDA
634

Właśnie odkryłem dobry sposób na ustawienie tytułu strony, jeśli używasz routingu:

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

Edycja : użycie ng-bindatrybutu zamiast curlies, {{}}aby nie wyświetlały się po załadowaniu

jkoreska
źródło
11
tak, ale twój przykład nie pokazuje, jak zmienić tytuł w $ routeChangeSuccess sparametryzowanych przez zmienne $ scope, co robi przykład @ tosha przy użyciu usługi strony. Więc możesz ustawić, title = "Blog"ale nie title = '{{"Blog post " + post.title}}'.
Eric Drechsel,
10
@ felix można uzyskać dostęp do tytułu jak current.titlerównież
Eldelshell
8
$ rootScope.title = bieżący. $ route.title; bez doble $$
david.sansay
7
Właśnie zaktualizowałem moją wersję Angular do kilku wersji (1.0.5 do 1.2.7) i to złamało mi kod. Używałem current.$routestarego kodu i działało. Wraz z aktualizacją potrzebne są podwójne $ na trasie. current.$$route
Tyler Forsythe
6
W automatycznej sekretarce, kiedy można zobaczyć '/Product/:id'. Czy jest jakiś sposób na uzyskanie :idwartości za pomocą tej metody? Próbowałem, title: function(params){return params.id;}ale nie działa ... Może używasz resolve?
mickaelb91,
190

Pamiętaj, że możesz również ustawić tytuł bezpośrednio za pomocą javascript, tj.

$window.document.title = someTitleYouCreated;

To nie ma wiązania danych, ale wystarczy, gdy umieszczenie ng-appw <html>tagu jest problematyczne. (Na przykład przy użyciu szablonów JSP, gdzie <head>jest zdefiniowane dokładnie w jednym miejscu, ale masz więcej niż jedną aplikację).

broc.seib
źródło
5
To był dla mnie jedyny sposób, aby działał w przeglądarce Internet Explorer, inne metody działały jednak w innych przeglądarkach
Maarten
4
Jak wspomniał Maarten, jest to jedyne podejście, które działa w ie7 i ie8
rob
33
Niesamowite, jak ludzie nie mogą się cofnąć i przekonać, jak łatwo można to zrobić bez
lunet
7
Nie do wiary. Było to o wiele prostsze niż wszystkie shenanigany, o których wspominali inni. Dzięki!
Leonard Teo
8
Używanie zwykłego „okna” jest w porządku - to działa bezpośrednio na DOM. „$ window” jest kanciaste i musisz go wstrzyknąć, aby z niego skorzystać. Tak czy inaczej zadziała.
broc.seib,
119

Deklarowanie ng-appna htmlelemencie zapewnia zasięg korzeni zarówno dla headi body.

Dlatego w swoim kontrolerze wstaw $rootScopei ustaw właściwość nagłówka:

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

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

i na twojej stronie:

<title ng-bind="header"></title>
Andy Hitchman
źródło
8
najlepsza odpowiedź na moją opinię. Posiadanie kontrolera na poziomie aplikacji w sposób opisany w zaakceptowanej odpowiedzi jest w tym przypadku bezużyteczne.
Nicolas Janel
1
uwielbiam jak lekkie jest to rozwiązanie i unika używania właściwości $$
tedwards947
Przyjęta odpowiedź powoduje niepotrzebne komplikacje i ryzyko. Ta wersja sprawia, że ​​jest to tak proste, jak ustawienie zmiennej.
special0ne
3
Jeśli nie chcesz używać $ rootScope, przynajmniej wyodrębnię to do usługi, abyś nie miał $ rootScope w kontrolerze.
Michael J. Calkins,
3
Chcę skorzystać z tego rozwiązania, ale jestem ciekawy, jakie są zalety korzystania z niego document.title = "App";
remarsz
43

Moduł angularjs-viewhead pokazuje mechanizm ustawiania tytułu na podstawie podglądu przy użyciu tylko niestandardowej dyrektywy.

Można go zastosować do istniejącego elementu widoku, którego treść jest już tytułem widoku:

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

... lub może być użyty jako samodzielny element, w którym to przypadku element będzie niewidoczny w renderowanym dokumencie i zostanie użyty tylko do ustawienia tytułu widoku:

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

Treść tej dyrektywy jest udostępniana w zakresie głównym jako viewTitle, więc można jej używać w elemencie title tak jak każdej innej zmiennej:

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

Można go również użyć w dowolnym innym miejscu, które może „zobaczyć” zakres główny. Na przykład:

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

To rozwiązanie umożliwia ustawienie tytułu za pomocą tego samego mechanizmu, który służy do kontrolowania pozostałej części prezentacji: szablonów AngularJS. Pozwala to uniknąć konieczności zaśmiecania kontrolerów za pomocą tej logiki prezentacji. Administrator musi udostępnić wszelkie dane, które zostaną wykorzystane do poinformowania o tytule, ale szablon ostatecznie określa sposób jego przedstawienia, i może użyć interpolacji wyrażeń i filtrów do normalnego wiązania danych zakresu.

(Uwaga: Jestem autorem tego modułu, ale odsyłam do niego tutaj tylko w nadziei, że pomoże to komuś innemu rozwiązać ten problem.)

Martin Atkins
źródło
4
Nie mogę uwierzyć, że to rozwiązanie nie zostało jeszcze ocenione. Większość innych to naprawdę złe wybory projektowe.
Martin Wawrusch
Uzgodnione, to powinno być najlepsze rozwiązanie. Lubię to znacznie lepiej niż deklarowanie kontrolera na poziomie strony do ustawiania tytułu. Do Twojej wiadomości: użycie tego z Angular v1.3.2 i angular-route-segment-v1.3.3 i działa jak urok.
Nate Barbettini,
Popieram to rozwiązanie;)
jkoreska
3
Napisałem nieco więcej o angularjs-viewhead i innym pokrewnym idei tutaj na moim blogu: apparently.me.uk/angularjs-view-specific-sidebars
Martin Atkins
Jeśli ponownie użyjesz tego samego widoku w widoku najwyższego i niższego poziomu, nadal możesz używać tytułu widoku z ng-if, np .: <h4 ng-if = "$ state.includes ('some-state')" view-title> Szczegóły dla {{...}} </h4> <h4 ng-if = "! $ state.includes ('some-state')"> Szczegóły dla {{...}} </ h4 >
2016
32

Oto dostosowane rozwiązanie, które działa dla mnie i nie wymaga wstrzyknięcia $ rootScope do kontrolerów w celu ustawienia tytułów stron specyficznych dla zasobów.

W szablonie głównym:

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

W konfiguracji routingu:

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

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

I w bloku uruchamiania:

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

Wreszcie w kontrolerze:

function ProductController($scope) {
    //Load product or use resolve in routing
    $scope.page.setTitle($scope.product.name);
}
Pan Hash
źródło
1
Tytuł ustawiony w ProductController ($ scope.page.setTitle) jest zastępowany przez $ rootScope. $ On ('$ routeChangeSuccess'. Ustawienie domyślnego tytułu w $ rootScope. $ On ('$ routeChangeStart' jest pod tym względem bezpieczniejszy.
Kristo Aun,
@ mr-hash: proponuję drobną korektę, idealną do istniejących projektów kątowych z wieloma trasami, ale bez tytułów. $rootScope.page.setTitle(current.$$route.title || current.$$route.controller.replace('Ctrl', ''));
Wygeneruje
1
pamiętaj, aby zdezynfekować dane wyjściowe w następujący sposób:this.title = title.replace('<', '&lt;').replace('>', '&gt;').replace(' & ', ' &amp; ') + ' | Site Name';
Henrik Stenbæk
Otrzymałem niezdefiniowany błąd, więc zmieniłem ostatni bit na: $ rootScope.page.title = bieżący. $$ route? obecny. $$ route.title + '| Nazwa witryny ”:„ Nazwa witryny ”;
Andy
15

Rozwiązanie jkoreska jest idealne, jeśli znasz tytuły wcześniej, ale może być konieczne ustawienie tytułu na podstawie danych uzyskanych z zasobu itp.

Moje rozwiązanie wymaga jednej usługi. Ponieważ rootScope jest podstawą wszystkich elementów DOM, nie musimy umieszczać kontrolera na elemencie HTML jak ktoś wspomniany

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

Wszystkie kontrolery, które muszą zmienić tytuł

app.controller('SomeController', function(Page){
    Page.setTitle("Some Title");
});
Deminetix
źródło
mały problem, kiedy odświeżysz stronę, w nazwie zakładki zobaczysz „{{title}}”, a po wyrenderowaniu strony zobaczysz tylko „Some Title”. rozwiązanie z fabryką nie ma takiego zachowania
Dmitri Algazin
5
zamiast tego {{title}}użyjng-bind='title'
Faradox
1
Zgadzam się z @Faradox ... użycie ng-bindzapobiega wyświetlaniu wstępnie interpolowanej składni przed faktyczną oceną tytułu. +100
Seth
11

Czysty sposób, który umożliwia dynamiczne ustawianie tytułu lub meta opisu. Na przykład używam interfejsu użytkownika routera, ale możesz używać ngRoute w ten sam sposób.

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
źródło
8

Alternatywnie, jeśli używasz interfejsu użytkownika routera :

index.html

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

Wytyczanie

$stateProvider
  .state('home', {
      url: '/',
      templateUrl: 'views/home.html',
      data: {
        title: 'Welcome Home.'
      }
  }
Nathan Kot
źródło
2
Nie mogę tego uruchomić. Mam ui-routeraktualizację adresu URL i zawartości w oparciu o mój stan i nie otrzymuję żadnych błędów ani ostrzeżeń, ale wydaje się, że nie mogę uzyskać dostępu do żadnej części obiektu konfiguracji stanu $state.current.[...]. Jakiej wersji ui-routerużyłeś do tego?
Moja edycja „Runtime Config” w odpowiedzi rozwiązuje problem, o którym wspomniałem w moim komentarzu powyżej. :) Jestem otwarty na pomysły, jeśli jest na to lepszy sposób.
to nie działa dla mnie, a dokumentacja API nie zawiera „tytułu” - czy nadal jest obsługiwany?
GraehamF,
7

Niestandardowe rozwiązanie oparte na zdarzeniach

Oto inne podejście, o którym inni nie wspominali tutaj (w tym piśmie).

Możesz użyć niestandardowych zdarzeń, takich jak:

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

Zaletą tego podejścia jest to, że nie wymaga zapisywania dodatkowych usług, a następnie wstrzykiwania ich do każdego kontrolera, który musi ustawić tytuł, a także (ab) nie używa $rootScope. Pozwala także ustawić dynamiczny tytuł (jak w przykładzie kodu), co nie jest możliwe przy użyciu niestandardowych atrybutów danych w obiekcie konfiguracji routera (o ile mi wiadomo).

Michael Bromley
źródło
5

W przypadku scenariuszy, w których nie masz aplikacji ngApp zawierającej titleznacznik, po prostu wstrzyknij usługę do kontrolerów, które muszą ustawić tytuł okna.

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

Przykład roboczy ... http://jsfiddle.net/8m379/1/

JeremyWeir
źródło
5

Jeśli nie masz kontroli nad elementem tytułowym (jak formularz internetowy asp.net), możesz skorzystać z tej opcji

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
źródło
4

Prosty i brudny sposób przy użyciu $rootScope:

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

Gdy dysponujesz danymi niezbędnymi do utworzenia tytułu, w kontrolerach:

$rootScope.title = 'Page X'
użytkownik1338062
źródło
4

Żadna z tych odpowiedzi nie była wystarczająco intuicyjna, dlatego stworzyłem małą dyrektywę, aby to zrobić. W ten sposób możesz zadeklarować tytuł na stronie, na której normalnie byś to zrobił, a także dynamicznie.

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

Musisz oczywiście zmienić nazwę modułu, aby pasowała do twojej.

Aby go użyć, po prostu wyświetl to w widoku, podobnie jak w przypadku zwykłego <title>tagu:

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

Możesz także dołączyć zwykły tekst, jeśli nie potrzebujesz go dynamicznie:

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

Możesz też użyć atrybutu, aby uczynić go bardziej przyjaznym dla IE:

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

Oczywiście możesz umieścić dowolny znacznik w znaczniku, w tym kod kątowy. W tym przykładzie będzie szukał $scope.titleTextdowolnego kontrolera, w którym aktualnie znajduje się niestandardowy tag.

Po prostu upewnij się, że nie masz na swojej stronie wielu tagów tytułów stron, bo inaczej się zlepią.

Przykład plunkera tutaj http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV . Musisz pobrać plik zip i uruchomić go lokalnie, aby zobaczyć zmianę tytułu.

MikeyB
źródło
Wymyśliłem coś podobnego. Zdecydowanie najbardziej intuicyjny w obsłudze i nie wymaga zakładania kontrolera html. W mojej dyrektywie wprowadzam również opcjonalną pageTitlePrefixstałą.
z0r
4

Uproszczone rozwiązanie dla routera kątowego:

HTML:

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

Blok App.js> 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);
   });
}]);
the_mishra
źródło
3

Oto inny sposób zmiany tytułu. Może nie jest tak skalowalny jak funkcja fabryczna (która może obsługiwać nieograniczoną liczbę stron), ale łatwiej mi było zrozumieć:

W moim index.html zacząłem tak:

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

Następnie utworzyłem częściowy o nazwie „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>

Potem wróciłem do „index.html” i dodałem nav.html, używając ng-include i ng-view dla moich stronicujących:

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

Zauważ, że ng-cloak? Nie ma to nic wspólnego z tą odpowiedzią, ale ukrywa stronę, dopóki nie zakończy się ładowanie, miły akcent :) Dowiedz się, jak tutaj: Angularjs - elementy ng-cloak / ng-show migają

Oto podstawowy moduł. Umieszczam go w pliku o nazwie „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"});
    });

}());

Jeśli spojrzysz na koniec modułu, zobaczysz, że mam stronę ze szczegółami w oparciu o: id. Jest to częściowy, który jest używany ze strony Crispy Critters. [Corny, wiem - może to strona, która celebruje wszelkiego rodzaju samorodki kurczaka;) W każdym razie możesz zaktualizować tytuł, gdy użytkownik kliknie dowolny link, więc na mojej głównej stronie Crispy Critters, która prowadzi do strony ze szczegółami o stworzeniach, właśnie tam poszedłaby aktualizacja $ root.title, tak jak widzieliście w nav.html powyżej:

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

Przepraszam, ale wietrznie, ale wolę post, który zawiera wystarczająco dużo szczegółów, aby go uruchomić. Zauważ, że przykładowa strona w dokumentach AngularJS jest nieaktualna i zawiera wersję 0.9 ng-bind-template. Widać, że nie jest tak bardzo inaczej.

Po namyśle: wiesz o tym, ale jest tu dla każdego; na dole index.html należy dołączyć app.js do modułu:

        <!-- APP -->
        <script type="text/javascript" src="js/app.js"></script>
    </body>
</html>
noogrub
źródło
2
Moim zdaniem nie używaj tego. Miksujesz dane (informacje) w widokach (prezentacja). Później bardzo trudno będzie znaleźć źródła tytułów rozrzucone po linkach HTML, które mogą być obecne w różnych miejscach widoku.
amit bakle
Ponieważ tytuł jest aktualizowany tylko po faktycznym kliknięciu linku , nie ustawia go poprawnie, gdy użytkownik po raz pierwszy wyląduje na stronie lub gdy użytkownik odświeży.
Mark Amery
3

Kiedy musiałem rozwiązać ten problem, nie mogłem umieścić tagu ng-appna stronie html, więc rozwiązałem go za pomocą usługi:

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
źródło
2

Niestandardowe rozwiązanie oparte na zdarzeniach inspirowane Michaela Bromleya

Nie byłem w stanie sprawić, aby działał z $ scope, więc spróbowałem z rootScope, może trochę bardziej brudny ... (szczególnie jeśli odświeżasz stronę, która nie rejestruje zdarzenia)

Ale bardzo podoba mi się pomysł, jak rzeczy są luźno powiązane.

Używam 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>

To działa dla mnie :)


Tomasz
źródło
1

Podczas gdy inni mogą mieć lepsze metody, byłem w stanie używać $ rootScope w moich kontrolerach, ponieważ każdy z moich widoków / szablonów ma inny kontroler. Musisz wprowadzić $ rootScope do każdego kontrolera. Chociaż może to nie być idealne, działa dla mnie, więc pomyślałem, że powinienem to przekazać. Jeśli przejrzysz stronę, dodasz wiązanie ng do tagu tytułu.

Przykładowy kontroler:

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

Przykładowy nagłówek 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>

Możesz także ustawić pageTitle i pageDescription na wartości dynamiczne, takie jak zwracanie danych z wywołania REST:

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

Znowu inni mogą mieć lepsze pomysły, jak do tego podejść, ale ponieważ używam renderowania wstępnego, moje potrzeby są zaspokojone.

Kode
źródło
0

Dzięki tosh shimayama za jego rozwiązanie.
Pomyślałem, że nie jest tak łatwo umieścić usługę bezpośrednio w $scope, więc oto moja niewielka odmiana: http://plnkr.co/edit/QJbuZZnZEDOBcYrJXWWs

Kontroler (który w pierwotnej odpowiedzi wydawał mi się zbyt głupi) tworzy obiekt ActionBar, a ten jest umieszczany w $ scope.
Obiekt jest odpowiedzialny za faktyczne wysłanie zapytania do usługi. Ukrywa również przed zakresem $ wywołanie, aby ustawić adres URL szablonu, który zamiast tego jest dostępny dla innych kontrolerów, aby ustawić adres URL.

superjos
źródło
0

Pan Hash miał jak dotąd najlepszą odpowiedź, ale poniższe rozwiązanie czyni go idealnym (dla mnie), dodając następujące korzyści:

  • Nie dodaje zegarków, co może spowolnić
  • W rzeczywistości automatyzuje to, co mogłem zrobić w kontrolerze
  • Nadal daje mi dostęp do kontrolera, jeśli nadal go chcę.
  • Bez dodatkowego wstrzykiwania

W routerze:

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

W bloku uruchamiania:

.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
źródło
-4

Lepszym i dynamicznym rozwiązaniem, które znalazłem, jest użycie $ watch do śledzenia zmian zmiennych, a następnie zaktualizowanie tytułu.

geolit
źródło