如何根据AngularJS局部视图动态更改标题?

mik*_*kel 410 javascript templates partial-views angularjs angular-routing

我使用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>
Run Code Online (Sandbox Code Playgroud)

我的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"; }
Run Code Online (Sandbox Code Playgroud)

jko*_*ska 633

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

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;
    });
}]);
Run Code Online (Sandbox Code Playgroud)

HTML:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <title ng-bind="'myApp &mdash; ' + title">myApp</title>
...
Run Code Online (Sandbox Code Playgroud)

编辑:使用ng-bind属性而不是curlies,{{}}因此它们不会在加载时显示

  • 关于使用ng-bind的提醒+1 (59认同)
  • 是的,但你的例子没有显示如何更改由$ scope变量参数化的$ routeChangeSuccess的标题,@ tosh使用Page服务的例子.所以你可以设置`title ="Blog"`但不能设置`title ='{{"Blog post"+ post.title}}'`. (11认同)
  • @felix你也可以访问像'current.title`这样的标题 (9认同)
  • $ rootScope.title = current.$ route.title; 没有doble $$ (8认同)
  • 我刚刚将Angular版本升级了几个版本(1.0.5到1.2.7),这在我的代码中打破了我.我在旧代码中使用`current.$ route`并且它正在运行.升级后,需要双$ $路线.`电流.$$ route` (7认同)
  • 在回答者的时候可以看到`'/ Product /:id'`.有没有办法用这个方法获得`:id`值?我试过`title:function(params){return params.id;}`但是不起作用......也许使用`resolve`? (6认同)
  • 这是一个非常好的解决方案,简洁干净. (3认同)
  • 这很棒,但唯一的一点是,$$航线被认为是"私人的". (2认同)

Tos*_*osh 340

您可以在<html>级别定义控制器.

 <html ng-app="app" ng-controller="titleCtrl">
   <head>
     <title>{{ Page.title() }}</title>
 ...
Run Code Online (Sandbox Code Playgroud)

您创建服务:Page并从控制器修改.

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

Page从控制器中注入并调用'Page.setTitle()'.

以下是具体示例:http: //plnkr.co/edit/0e7T6l

  • @ArthurFrankel只需使用ng-bind(例如ng-bind ="Page.title()") (52认同)
  • 这个例子太棒了.我有一个后续,但在初始加载时,您可以在标题中看到{{Page.title()}}文本(非常快).我不认为你可以使用ng-cloak,因为它不在体内.有什么建议可以避免吗? (11认同)
  • 嗯......我不确定是否将服务直接放入$ scope中,在AngularJS架构中被视为*nice*.也许最好在$ scope中放入一个Controller函数,然后让这个函数查询服务. (10认同)
  • 我个人更喜欢在`$ rootScope`上设置标题,而不是创建一个额外的控制器. (6认同)
  • 或者我们可以在标题标签中指定控制器,不需要html标题上的全局控制器:<title ng-controller ="titleCtrl"> {{Page.title()}} </ title> (2认同)

bro*_*eib 188

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

$window.document.title = someTitleYouCreated;
Run Code Online (Sandbox Code Playgroud)

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

  • 令人惊讶的是人们如何在没有范围和工厂的情况下退后一步,看看这件事是多么容易 (32认同)
  • 使用普通的"窗口"很好 - 这直接作用于DOM.'$ window'是一个有角度的东西,你必须注入它才能使用它.无论哪种方式都可行. (8认同)
  • 难以置信的.这比其他人提到的所有诡计都要简单得多.谢谢! (7认同)
  • 这是让它在我的Internet Explorer上运行的唯一方法,其他方法也适用于其他浏览器 (5认同)
  • 正如Maarten所说,这是唯一适用于ie7和ie8的方法 (4认同)
  • 很好的直接方法,让你想起显而易见的.我简单地将它作为setTitle()函数包含在我的'ui'服务中,注入$ window依赖项,并且由于我的服务在我的所有控制器中,现在可以在任何我需要的地方调用ui.setTitle('example title')控制器. (2认同)
  • 绝对是最好的答案!如此轻盈和直接. (2认同)

小智 119

声明ng-app的上html元件提供根范围两者的headbody.

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

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

function Test2Ctrl($rootScope, $scope, $http) { $rootScope.header = "Test 2"; }
Run Code Online (Sandbox Code Playgroud)

并在您的页面中:

<title ng-bind="header"></title>
Run Code Online (Sandbox Code Playgroud)

  • 我的意见最好的答案.在这种情况下,如在接受的答案中描述的那样在ng-app级别上具有控制器是无用的. (8认同)
  • 如果您已经开始使用$ rootScope了,我至少会将其解析为服务,因此您的控制器中没有$ rootScope. (3认同)
  • 我想使用这个解决方案,但我很好奇使用它的优点是什么超过`document.title ="App"`; (3认同)

Mar*_*ins 42

模块angularjs-viewhead显示了一种机制,可以仅使用自定义指令在每个视图的基础上设置标题.

它可以应用于其内容已经是视图标题的现有视图元素:

<h2 view-title>About This Site</h2>
Run Code Online (Sandbox Code Playgroud)

...或者它可以用作独立元素,在这种情况下,元素在渲染文档中是不可见的,并且仅用于设置视图标题:

<view-title>About This Site</view-title>
Run Code Online (Sandbox Code Playgroud)

该指令的内容在根作用域中可用viewTitle,因此它可以像title任何其他变量一样用在title元素上:

<title ng-bind-template="{{viewTitle}} - My Site">My Site</title>
Run Code Online (Sandbox Code Playgroud)

它也可以用于任何可以"看到"根范围的其他位置.例如:

<h1>{{viewTitle}}</h1>
Run Code Online (Sandbox Code Playgroud)

此解决方案允许通过用于控制演示文稿其余部分的相同机制设置标题:AngularJS模板.这避免了使用这种表示逻辑使控制器混乱的需要.控制器需要提供将用于通知标题的任何数据,但模板最终确定如何呈现它,并且可以使用表达式插值和过滤器正常绑定到范围数据.

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

  • 无法相信这个解决方案还没有得到更多的支持.其他大多数都是糟糕的设计选择. (4认同)
  • 我在博客上写了更多关于angularjs-viewhead和另一个相关想法的文章:http://apparently.me.uk/angularjs-view-specific-sidebars/ (3认同)

Mr *_*ash 31

这是一个适用于我的解决方案,它不需要将$ rootScope注入控制器来设置特定于资源的页面标题.

在主模板中:

<html data-ng-app="myApp">
    <head>
    <title data-ng-bind="page.title"></title>
    ...
Run Code Online (Sandbox Code Playgroud)

在路由配置中:

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

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

并在运行块中:

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');
    });
}]);
Run Code Online (Sandbox Code Playgroud)

最后在控制器中:

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


Dem*_*tix 15

如果您事先了解标题,jkoreska的解决方案是完美的,但您可能需要根据从资源获得的数据等设置标题.

我的解决方案需要单一服务.由于rootScope是所有DOM元素的基础,因此我们不需要像所提到的那样在html元素上放置控制器

Page.js

app.service('Page', function($rootScope){
    return {
        setTitle: function(title){
            $rootScope.title = title;
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

index.jade

doctype html
html(ng-app='app')
head
    title(ng-bind='title')
// ...
Run Code Online (Sandbox Code Playgroud)

所有需要更改标题的控制器

app.controller('SomeController', function(Page){
    Page.setTitle("Some Title");
});
Run Code Online (Sandbox Code Playgroud)

  • 而``{{title}}`使用`ng-bind ='title' (5认同)

Ale*_*oka 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'
        });
    }]);
Run Code Online (Sandbox Code Playgroud)

HTML:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <title ng-bind="meta.title + ' | My App'">myApp</title>
...
Run Code Online (Sandbox Code Playgroud)


Nat*_*Kot 9

或者,如果您使用的是ui-router:

的index.html

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <title ng-bind="$state.current.data.title || 'App'">App</title>
Run Code Online (Sandbox Code Playgroud)

路由

$stateProvider
  .state('home', {
      url: '/',
      templateUrl: 'views/home.html',
      data: {
        title: 'Welcome Home.'
      }
  }
Run Code Online (Sandbox Code Playgroud)

  • 我无法让这个工作..我有'ui-router`根据我的状态更新URL和内容,我没有得到任何错误或警告,但我似乎无法访问状态配置对象的任何部分通过`$ state.current.[...]`.您使用什么版本的`ui-router`来执行此操作? (2认同)

Mic*_*ley 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);
});
Run Code Online (Sandbox Code Playgroud)

这种方法的优点是不需要编写额外的服务,然后注入每个需要设置标题的控制器,也不会(ab)使用$rootScope.它还允许您设置动态标题(如代码示例中所示),这在路由器的配置对象上使用自定义数据属性是不可能的(据我所知).


Jer*_*eir 5

对于您没有包含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;
        }
    };
});
Run Code Online (Sandbox Code Playgroud)

工作示例... http://jsfiddle.net/8m379/1/


小智 5

如果您无法控制title元素(如asp.net Web表单),可以使用以下内容

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;
        });
    });
Run Code Online (Sandbox Code Playgroud)