如何动态改变头部基于AngularJS的部分视图?

我使用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"; }
271257 次浏览

你可以在<html>级别定义控制器。

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

创建service: 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

这里有一种不同的方式来进行标题更改。也许不像工厂函数那样可扩展(可以处理无限的页面),但对我来说更容易理解:

在我的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”,使用ng-include和ng-view为我的部分添加nav.html:

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

注意到那件斗篷了吗?它与这个答案没有任何关系,但它会隐藏页面,直到它完成加载,一个很好的触摸:)在这里学习如何:Angularjs - ng-斗篷/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的生物细节页面。这是从脆皮动物页面使用的部分。[老土,我知道-也许这是一个庆祝各种鸡块的网站;)无论如何,当用户点击任何链接时,你可以更新标题,所以在我的主脆皮动物页面,通往动物细节页面,这是$根。标题更新会这样,就像你在上面的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文档中的示例页面已经过时,显示的是0.9版本的ng-bind-template。你可以看到并没有太大的不同。

事后想:你知道这一点,但它是为其他人而存在的;在index.html的底部,必须包含app.js模块:

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

我刚刚发现了一个很好的方法来设置你的页面标题,如果你使用路由:

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属性代替\{\{}},这样它们在加载时不会显示

注意,您也可以直接使用javascript设置标题,即,

$window.document.title = someTitleYouCreated;

它没有数据绑定,但当将ng-app放在<html>标记中有问题时,它就足够了。(例如,使用JSP模板,其中<head>定义在一个地方,但你有多个应用程序。)

感谢废话shimayama的解决方案 我认为直接将服务放入$scope中不太干净,所以这里是我对它的轻微变化:http://plnkr.co/edit/QJbuZZnZEDOBcYrJXWWs

控制器(在最初的回答中,对我来说似乎有点太笨了)创建了一个ActionBar对象,这个对象被填充到$scope.
对象负责实际查询服务。它还从$作用域调用隐藏了来设置模板URL,而其他控制器可以使用它来设置URL

html元素上声明ng-appheadbody提供了根作用域。

因此在你的控制器中注入$rootScope并在this上设置一个header属性:

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


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

在你的页面中:

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

对于没有包含title标记的ngApp的场景,只需向需要设置窗口标题的控制器注入服务。

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;
}
};
});
< p >工作示例…… http://jsfiddle.net/8m379/1/ < / p >

这是一个适合我的解决方案,它不需要注入$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);
}

如果你不能控制标题元素(如asp.net web form),这里有一些东西你可以使用

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

使用$rootScope的简单而肮脏的方法:

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

在你的控制器中,当你拥有创建标题所需的数据时,执行以下操作:

$rootScope.title = 'Page X'

模块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模板。这避免了用这种表示逻辑使控制器混乱的需要。控制器需要提供将用于通知标题的任何数据,但模板对如何表示它做出最终决定,并且可以正常使用表达式插值和过滤器绑定到作用域数据。

(免责声明:我是这个模块的作者,但我在这里引用它只是希望它能帮助其他人解决这个问题。)

如果你事先知道标题,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");
});

自定义基于事件的解决方案

这里有另一种方法没有被其他方法提到(在撰写本文时)。

你可以像这样使用自定义事件:

// 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。它还允许你设置一个动态标题(如代码示例中所示),这是不可能在路由器的配置对象上使用自定义数据属性的(至少据我所知)。

一个干净的方式,允许动态设置标题或元描述。在示例中,我使用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>
...

这些答案似乎都不够直观,所以我创建了一个小指令来做这件事。这种方式允许您在页面中声明标题,而通常情况下是这样做的,并允许它是动态的。

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>

当然,你可以在标签中放入任何你想要的文本,包括Angular代码。在这个例子中,它将在custom-title标签当前所在的控制器中查找$scope.titleText

只要确保你的页面上没有多个页面标题标签,否则它们会互相攻击。

活塞的例子在这里http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV。您必须下载压缩文件并在本地运行,才能看到标题的变化。

或者,如果你正在使用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.'
}
}

哈希先生是迄今为止最好的答案,但下面的解决方案通过添加以下好处使它成为理想的(对我来说):

  • 没有手表,这会让事情变慢
  • 实际上自动化了我在控制器中所做的
  • 如果我想要,仍然可以从控制器访问它。
  • 无需额外注射

在路由器中:

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

我发现的更好的动态解决方案是使用$watch跟踪变量更改,然后更新标题。

虽然其他人可能有更好的方法,但我能够在我的控制器中使用$rootScope,因为我的每个视图/模板都有一个不同的控制器。您需要在每个控制器中注入$rootScope。虽然这可能不太理想,但它对我来说很有用,所以我想我应该把它传下去。如果检查页面,它会将ng-binding添加到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;
});

同样,其他人可能对如何处理这个问题有更好的想法,但由于我使用预渲染,我的需求得到了满足。

当我必须解决这个问题时,我不能将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;
}
};


});

angular-ui-router的简单解决方案:

HTML:

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

myApp. js >。配置块

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

自定义基于事件的解决方案,灵感来自迈克尔·布罗姆利

我不能使它与$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>

这对我很有用:)