Как динамически изменить заголовок на основе частичного представления AngularJS?

411

Я использую ng-view для включения частичных представлений AngularJS и хочу обновить теги заголовка страницы и заголовка h1 на основе включенного представления. Это выходит за рамки контроллеров частичного представления, и поэтому я не могу понять, как связать их с набором данных в контроллерах.

Если бы это был ASP.NET MVC, вы могли бы использовать @ViewBag для этого, но я не знаю эквивалента в AngularJS. Я искал общие службы, события и т. Д., Но до сих пор не могу заставить его работать. Любой способ изменить мой пример, чтобы он работал, будет высоко ценится.

Мой 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>

Мой 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"; }
Микель
источник
Этот комментарий может быть поздно, но я хочу добавить. cssfacts.com/simple-dynamic-meta-tags-in-angularjs Это может быть полезно для установки динамических метасов. Вы просто измените мета-переменную $ rootScope.
Камуран Сёнечек

Ответы:

342

Вы можете определить контроллер на <html>уровне.

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

Вы создаете сервис: Pageи модифицируете из контроллеров.

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

Введите Pageи вызовите Page.setTitle () из контроллеров.

Вот конкретный пример: http://plnkr.co/edit/0e7T6l

вздор
источник
11
хм ... я не уверен, что размещение сервиса прямо в $ scope считается хорошим в архитектуре AngularJS. Возможно, было бы лучше поместить в $ scope функцию Controller, а затем позволить этой функции запрашивать службу.
Superjos
11
Этот пример был потрясающим. У меня есть одно продолжение, хотя при начальной загрузке вы можете увидеть текст {{Page.title ()}} в заголовке (очень быстро). Я не думаю, что вы можете использовать нг-плащ, так как его нет в теле. Любые предложения, чтобы избежать этого?
Артур Франкель
52
@ArthurFrankel Просто используйте ng-bind (например, ng-bind = "Page.title ()")
Pius Uzamere
2
или мы можем указать контроллер в теге title, нет необходимости в глобальном контроллере в заголовке html: <title ng-controller = "titleCtrl"> {{Page.title ()}} </ title>
Дмитрий Алгазин
6
Я лично предпочитаю устанавливать заголовок $rootScopeвместо создания дополнительного контроллера.
DDA
634

Я только что нашел хороший способ установить заголовок страницы, если вы используете маршрутизацию:

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

Редактировать : используя ng-bindатрибут вместо фигурных скобок, {{}}чтобы они не отображались при загрузке

jkoreska
источник
11
верно, но ваш пример не показывает, как изменить заголовок в $ routeChangeSuccess, параметризованный переменными $ scope, как это делает пример @ tosh с использованием службы Page. Таким образом, вы можете установить, title = "Blog"но не title = '{{"Blog post " + post.title}}'.
Эрик Дрехсель
10
@felix вы можете получить доступ к названию, как current.titleтакже
Eldelshell
8
$ rootScope.title = current. $ route.title; без дубликата $$
david.sansay
7
Я только что обновил свою версию Angular на несколько версий (1.0.5 до 1.2.7), и это сломало меня в моем коде. Я использовал current.$routeв старом коде, и он работал. При обновлении необходим двойной $ на маршруте. current.$$route
Тайлер Форсайт
6
В ответчике когда сможете увидеть '/Product/:id'. Есть ли способ получить :idзначение с помощью этого метода? Я пытался, title: function(params){return params.id;}но не работает ... Может быть, с помощью resolve?
mickaelb91
190

Обратите внимание, что вы также можете установить заголовок непосредственно с помощью JavaScript, т.е.

$window.document.title = someTitleYouCreated;

Это не имеет привязки данных, но достаточно , если положить ng-appв <html>теге является проблематичным. (Например, при использовании шаблонов JSP, где <head>определено ровно в одном месте, у вас есть несколько приложений.)

broc.seib
источник
5
Это был единственный способ заставить его работать в Internet Explorer, другие методы работали в других браузерах
Maarten
4
Как упоминал Мартен, это единственный подход, который работает в ie7 и ie8
rob
33
Удивительно, как люди не могут отступить и увидеть, как легко это можно сделать без
границ
7
Невероятно. Это было намного проще, чем все махинации, которые упоминали другие. Спасибо!
Леонард Тео
8
Использовать простое «окно» хорошо - это напрямую влияет на DOM. '$ window' - угловатая вещь, и вы должны ввести ее, чтобы использовать. В любом случае будет работать.
broc.seib 22.12.14
119

Объявление ng-appна htmlэлементе обеспечивает корневой простор для как headи body.

Поэтому в вашем контроллере введите $rootScopeи установите свойство заголовка для этого:

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

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

и на вашей странице:

<title ng-bind="header"></title>
Энди Хитчман
источник
8
лучший ответ на мой взгляд. Иметь контроллер на уровне ng-app, как описано в принятом ответе, в этом случае бесполезно.
Николас Джанель
1
Мне нравится, насколько легким является это решение, и оно избегает использования $$ properties
tedwards947
Принятый ответ добавляет ненужные осложнения и риски. Эта версия делает это так же просто, как установка переменной.
special0ne
3
Если вы не можете использовать $ rootScope, я бы по крайней мере извлек это в службу, чтобы у вас не было $ rootScope в вашем контроллере.
Майкл Дж. Калкинс
3
Я хочу использовать это решение, но мне любопытно, каковы преимущества его использования document.title = "App";
Restrsh
43

Модуль angularjs-viewhead показывает механизм для установки заголовка для каждого просмотра с использованием только пользовательской директивы.

Его можно применить к существующему элементу представления, содержимое которого уже является заголовком представления:

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

... или его можно использовать как отдельный элемент, в этом случае этот элемент будет невидимым в отображаемом документе и будет использоваться только для установки заголовка представления:

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

Содержимое этой директивы доступно в корневой области как viewTitle, поэтому его можно использовать в элементе title, как и в любой другой переменной:

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

Его также можно использовать в любом другом месте, которое может «видеть» корневую область видимости. Например:

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

Это решение позволяет устанавливать заголовок с помощью того же механизма, который используется для управления остальной частью презентации: шаблоны AngularJS. Это позволяет избежать необходимости загромождать контроллеры этой логикой представления. Контроллер должен предоставлять любые данные, которые будут использоваться для информирования заголовка, но шаблон окончательно определяет, как его представлять, и может использовать интерполяцию выражений и фильтры для привязки к данным области как обычно.

(Отказ от ответственности: я являюсь автором этого модуля, но я ссылаюсь на него здесь только в надежде, что он поможет кому-то еще решить эту проблему.)

Мартин Аткинс
источник
4
Не могу поверить, что за это решение больше не голосовали. Большинство других действительно плохих дизайнерских решений.
Мартин Вавруш,
Согласитесь, это должно быть лучшим решением. Мне это нравится намного лучше, чем объявление контроллера на уровне страницы для установки заголовка. К вашему сведению: используйте это с Angular v1.3.2 и angular-route-сегмента v1.3.3, и это работает как шарм.
Нейт Барбеттини
Я одобряю это решение;)
jkoreska
3
Я написал немного больше об angularjs-viewhead и другой связанной с этим идее здесь, в моем блоге: очевидно.me.uk/
Мартин Аткинс
Если повторно использовать один и тот же вид на верхнем уровне и на уровне подуровня, можно по-прежнему использовать view-title с ng-if, например: <h4 ng-if = "$ state.include ('some-state')" view-title> Подробности для {{...}} </ h4> <h4 ng-if = "! $ state.includes ('some-state')">> Детали для {{...}} </ h4 >
НАРЭ
32

Вот адаптированное решение, которое работает для меня, которое не требует внедрения $ rootScope в контроллеры для установки заголовков страниц для конкретных ресурсов.

В мастер-шаблоне:

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

В конфиге маршрутизации:

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

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

И в блоке бега:

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

Наконец-то в контроллере:

function ProductController($scope) {
    //Load product or use resolve in routing
    $scope.page.setTitle($scope.product.name);
}
Мистер хэш
источник
1
Набор заголовков в ProductController ($ scope.page.setTitle) переопределяется $ rootScope. $ On ('$ routeChangeSuccess'. Установка заголовка по умолчанию в $ rootScope. $ On ('$ routeChangeStart' безопаснее в этом отношении.
Кристо Аун
@ mr-hash: я предлагаю небольшую настройку, которая идеально подходит для существующих угловых проектов с большим количеством маршрутов, но без заголовков. Он будет генерировать заголовок из имени контроллера, если заголовок не определен на маршруте:$rootScope.page.setTitle(current.$$route.title || current.$$route.controller.replace('Ctrl', ''));
mikhail-t
1
Не забудьте санировать вывод следующим образом:this.title = title.replace('<', '&lt;').replace('>', '&gt;').replace(' & ', ' &amp; ') + ' | Site Name';
Хенрик Стенбек
Я получил неопределенную ошибку, поэтому я изменил последний бит на: $ rootScope.page.title = current. $$ route? текущий. $$ route.title + '| Имя сайта »:« Имя сайта »;
Энди
15

Решение jkoreska идеально подходит, если вы знаете заголовки заранее, но вам может потребоваться установить заголовок на основе данных, которые вы получаете от ресурса и т. д.

Мое решение требует одного сервиса. Поскольку rootScope является основой всех элементов DOM, нам не нужно помещать контроллер в элемент HTML, как кто-то упоминал

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

Все контроллеры, которые должны изменить заголовок

app.controller('SomeController', function(Page){
    Page.setTitle("Some Title");
});
Deminetix
источник
небольшая проблема: когда вы обновляете страницу, в имени вкладки вы видите «{{title}}», а после рендеринга страницы вы видите только «Some Title». решение с завода не имеет такого поведения
Дмитрий Алгазин
5
вместо этого {{title}}используйтеng-bind='title'
Фарадокс
1
Согласитесь с @Faradox ... using ng-bindпредотвращает отображение предварительно интерполированного синтаксиса до того, как заголовок действительно оценивается. +100
Сет
11

Чистый способ, который позволяет динамически устанавливать заголовок или мета-описание. В примере я использую ui-router, но вы можете использовать ngRoute таким же образом.

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

В качестве альтернативы, если вы используете ui-router :

index.html

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

Маршрутизация

$stateProvider
  .state('home', {
      url: '/',
      templateUrl: 'views/home.html',
      data: {
        title: 'Welcome Home.'
      }
  }
Натан Кот
источник
2
Я не могу заставить это работать ... Я ui-routerобновляю URL и контент на основе своего состояния, и я не получаю ошибок или предупреждений, но я не могу получить доступ к какой-либо части объекта конфигурации состояния через $state.current.[...]. Какую версию ui-routerвы использовали для этого?
Моя «Runtime Config», редактирующая ответ, решает проблему, о которой я упоминал в своем комментарии выше. :) Я открыт для идей, если есть лучший способ сделать это все же.
это не работает для меня, и 'title' не найден в документации API - это все еще поддерживается?
GraehamF
7

Индивидуальное решение на основе событий

Вот еще один подход, который не был упомянут другими здесь (на момент написания статьи).

Вы можете использовать пользовательские события, например, так:

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

Этот подход имеет то преимущество, что не требует написания дополнительных сервисов и их последующего внедрения в каждый контроллер, которому требуется установить заголовок, а также не использует (ab) $rootScope. Это также позволяет вам установить динамический заголовок (как в примере кода), что невозможно при использовании пользовательских атрибутов данных в объекте конфигурации маршрутизатора (насколько я знаю, по крайней мере).

Майкл Бромли
источник
5

Для сценариев, в которых у вас нет ngApp, содержащего titleтег, просто внедрите сервис в контроллеры, которым необходимо установить заголовок окна.

var app = angular.module('MyApp', []);

app.controller('MyController', function($scope, SomeService, Title){
    var serviceData = SomeService.get();
    Title.set("Title of the page about " + serviceData.firstname);
});

app.factory('SomeService', function ($window) {
    return {
        get: function(){
            return { firstname : "Joe" };
        }
    };
});

app.factory('Title', function ($window) {
    return {
        set: function(val){
            $window.document.title = val;
        }
    };
});

Рабочий пример ... http://jsfiddle.net/8m379/1/

JeremyWeir
источник
5

Если вы не можете контролировать элемент title (например, веб-форму asp.net), вот что вы можете использовать

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
источник
4

Простой и грязный способ использования $rootScope:

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

В ваших контроллерах, когда у вас есть данные, необходимые для создания заголовка, выполните:

$rootScope.title = 'Page X'
user1338062
источник
4

Ни один из этих ответов не казался достаточно интуитивным, поэтому я создал небольшую директиву для этого. Этот способ позволяет вам объявить заголовок на странице, где обычно это делается, и позволяет ему быть динамичным.

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

Вам, конечно, нужно изменить имя модуля, чтобы оно соответствовало вашему.

Чтобы использовать это, просто бросьте это в своем представлении, так же, как вы сделали бы для обычного <title>тега:

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

Вы также можете просто включить простой текст, если вам это не нужно, динамически:

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

Кроме того, вы можете использовать атрибут, чтобы сделать его более удобным для IE:

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

Вы можете поместить любой текст в тег, который вы хотите, включая угловой код. В этом примере он будет искать $scope.titleTextв любом контроллере, в котором находится тег пользовательского заголовка.

Просто убедитесь, что на вашей странице нет нескольких тегов заголовка страницы, иначе они будут слипаться.

Пример плунжера здесь http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV . Вам нужно скачать zip и запустить его локально, чтобы увидеть изменение названия.

MikeyB
источник
Я придумал что-то подобное. Безусловно, наиболее интуитивно понятен в использовании и не требует установки контроллера html. В моей директиве я также добавляю необязательную pageTitlePrefixконстанту.
z0r
4

Упрощенное решение для angular-ui-router:

HTML:

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

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
источник
3

Вот другой способ сделать изменения названия. Возможно, не так масштабируемо, как фабричная функция (которая могла бы обрабатывать неограниченное количество страниц), но мне было легче понять:

В моем index.html я начал так:

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

Затем я сделал партиал под названием «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>

Затем я вернулся к «index.html» и добавил nav.html, используя ng-include и ng-view для моих партиалов:

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

Заметьте, что нг-плащ? Он не имеет никакого отношения к этому ответу, но он скрывает страницу до тех пор, пока она не загрузится, приятное прикосновение :) Узнайте, как здесь: Angularjs - элементы ng-cloak / ng-show мигают

Вот основной модуль. Я положил его в файл с именем "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"});
    });

}());

Если вы посмотрите в конец модуля, то увидите, что у меня есть страница с подробным описанием критериев, основанная на: id. Это часть, которая используется на странице Crispy Critters. [Корни, я знаю - может быть, это сайт, который празднует все виды куриных самородков;) В любом случае, вы можете обновить заголовок, когда пользователь нажимает на любую ссылку, поэтому на моей главной странице Crispy Critters, которая ведет на страницу с подробностями о существе, вот куда пойдет обновление $ root.title, как вы видели в nav.html выше:

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

Извините, что так ветрено, но я предпочитаю пост, в котором достаточно подробностей, чтобы начать работу. Обратите внимание, что пример страницы в документации AngularJS устарел и показывает версию ng-bind-template 0,9. Вы можете видеть, что это не так сильно отличается.

Запоздалая мысль: вы знаете это, но это здесь для всех остальных; в нижней части index.html необходимо включить app.js с модулем:

        <!-- APP -->
        <script type="text/javascript" src="js/app.js"></script>
    </body>
</html>
noogrub
источник
2
Мое мнение, не используйте это. Вы смешиваете данные (информацию) в представлениях (презентации). Позже будет очень трудно найти источники заголовков, разбросанные по всем вашим HTML-ссылкам, которые могут присутствовать в различных местах представления ...
amit bakle
Поскольку заголовок обновляется только после фактического нажатия на ссылку , заголовок не устанавливается правильно, когда пользователь впервые попадает на страницу или когда пользователь обновляется.
Марк Эмери
3

Когда мне пришлось решить эту проблему, я не мог разместить тег ng-appна странице html, поэтому я решил это с помощью службы:

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

Специальное решение на основе событий, вдохновленное Майклом Бромли

Я не смог заставить его работать с $ scope, поэтому я попытался с rootScope, возможно, немного более грязным ... (особенно если вы делаете обновление на странице, которая не регистрирует событие)

Но мне действительно нравится идея о том, как вещи слабо связаны.

Я использую 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>

Это работает для меня :)


Томас
источник
1

В то время как другие могут иметь лучшие методы, я смог использовать $ rootScope в своих контроллерах, так как каждый из моих представлений / шаблонов имеет отдельный контроллер. Вам нужно будет вставить $ rootScope в каждый контроллер. Хотя это может и не быть идеальным, оно работает для меня, поэтому я подумал, что должен это передать. Если вы просматриваете страницу, она добавляет привязку ng к тегу title.

Пример контроллера:

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

Пример заголовка 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>

Вы также можете установить динамические значения для pageTitle и pageDescription, например, для возврата данных из вызова REST:

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

Снова, у других могут быть лучшие идеи относительно того, как приблизиться к этому, но так как я использую предварительный рендеринг, мои потребности удовлетворяются.

Kode
источник
0

Спасибо Тошу Симаяма за его решение.
Я думал, что не очень-то чисто поставить сервис прямо в $scope, так что вот мое небольшое изменение: http://plnkr.co/edit/QJbuZZnZEDOBcYrJXWWs

Контроллер (который в первоначальном ответе показался мне слишком тупым) создает объект ActionBar, и этот объект помещается в $ scope.
Объект отвечает за фактический запрос сервиса. Он также скрывает от $ scope вызов для установки URL-адреса шаблона, который вместо этого доступен другим контроллерам для установки URL-адреса.

superjos
источник
0

У Мистера Хэша был лучший ответ, но приведенное ниже решение делает его идеальным (для меня), добавляя следующие преимущества:

  • Не добавляет часов, которые могут замедлить ход событий
  • На самом деле автоматизирует то, что я мог бы сделать в контроллере, пока
  • По-прежнему дает мне доступ с контроллера, если я все еще хочу это.
  • Никаких дополнительных инъекций

В роутере:

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

В блоке выполнения:

.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

Лучшее и динамичное решение, которое я нашел, - это использовать $ watch для отслеживания изменений переменных, а затем обновить заголовок.

geolyth
источник