Javascript 如何基于 AngularJS 局部视图动态更改标题?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12506329/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 10:33:58  来源:igfitidea点击:

How to dynamically change header based on AngularJS partial view?

javascriptangularjstemplatespartial-viewsangular-routing

提问by mikel

I am using ng-view to include AngularJS partial views, and I want to update the page title and h1 header tags based on the included view. These are out of scope of the partial view controllers though, and so I can't figure out how to bind them to data set in the controllers.

我正在使用 ng-view 来包含 AngularJS 部分视图,并且我想根据包含的视图更新页面标题和 h1 标题标签。但是,这些超出了局部视图控制器的范围,因此我无法弄清楚如何将它们绑定到控制器中的数据集。

If it was ASP.NET MVC you could use @ViewBag to do this, but I don't know the equivalent in AngularJS. I've searched about shared services, events etc but still can't get it working. Any way to modify my example so it works would be much appreciated.

如果是 ASP.NET MVC,您可以使用 @ViewBag 来执行此操作,但我不知道 AngularJS 中的等效项。我搜索了共享服务、事件等,但仍然无法正常工作。任何修改我的示例使其有效的方法将不胜感激。

My HTML:

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

My JavaScript:

我的 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"; }

采纳答案by Tosh

You could define controller at the <html>level.

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

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

You create service: Pageand modify from controllers.

您创建 service:Page并从控制器进行修改。

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

Inject Pageand Call 'Page.setTitle()' from controllers.

Page从控制器注入并调用“Page.setTitle()”。

Here is the concrete example: http://plnkr.co/edit/0e7T6l

这是具体的例子:http: //plnkr.co/edit/0e7T6l

回答by jkoreska

I just discovered a nice way to set your page title if you're using routing:

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

JavaScript:

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:

HTML:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <title ng-bind="'myApp &mdash; ' + title">myApp</title>
...

Edit: using the ng-bindattribute instead of curlies {{}}so they don't show on load

编辑:使用ng-bind属性而不是卷曲,{{}}这样它们就不会在加载时显示

回答by broc.seib

Note that you can also set the title directly with javascript, i.e.,

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

$window.document.title = someTitleYouCreated;

This does not have data binding, but it suffices when putting ng-appin the <html>tag is problematic. (For example, using JSP templates where <head>is defined in exactly one place, yet you have more than one app.)

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

回答by Andy Hitchman

Declaring ng-appon the htmlelement provides root scope for both the headand body.

ng-apphtml元素上声明为head和提供根范围body

Therefore in your controller inject $rootScopeand set a header property on this:

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

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

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

and in your page:

并在您的页面中:

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

回答by Martin Atkins

The module angularjs-viewheadshows a mechanism to set the title on a per-view basis using only a custom directive.

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

It can either be applied to an existing view element whose content is already the view title:

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

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

...or it can be used as a standalone element, in which case the element will be invisible in the rendered document and will only be used to set the view title:

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

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

The content of this directive is made available in the root scope as viewTitle, so it can be used on the title element just like any other variable:

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

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

It can also be used in any other spot that can "see" the root scope. For example:

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

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

This solution allows the title to be set via the same mechanism that is used to control the rest of the presentation: AngularJS templates. This avoids the need to clutter controllers with this presentational logic. The controller needs to make available any data that will be used to informthe title, but the template makes the final determination on how to present it, and can use expression interpolation and filters to bind to scope data as normal.

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

(Disclaimer: I am the author of this module, but I'm referencing it here only in the hope that it will help someone else to solve this problem.)

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

回答by Mr Hash

Here is an adapted solution that works for me which doesn't require injection of $rootScope into controllers for setting resource specific page titles.

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

In the master template:

在主模板中:

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

In the routing config:

在路由配置中:

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

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

And in the run block:

在运行块中:

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

Finally in the controller:

最后在控制器中:

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

回答by Deminetix

jkoreska's solution is perfect if you know the titles before hand, but you may need to set the title based on data you get from a resource etc.

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

My solution requires a single service. Since the rootScope is the base of all DOM elements, we don't need to put a controller on the html element like someone mentioned

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

Page.js

页面.js

app.service('Page', function($rootScope){
    return {
        setTitle: function(title){
            $rootScope.title = title;
        }
    }
});

index.jade

索引.jade

doctype html
html(ng-app='app')
head
    title(ng-bind='title')
// ...

All controllers that need to change title

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

app.controller('SomeController', function(Page){
    Page.setTitle("Some Title");
});

回答by Alex Soroka

A clean way that allow dynamically setting title or meta description. In example I use ui-router but you can use ngRoute in same way.

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

HTML:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <title ng-bind="meta.title + ' | My App'">myApp</title>
...

回答by Nathan Kot

Alternatively, if you are using ui-router:

或者,如果您使用ui-router

index.html

索引.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.'
      }
  }

回答by Michael Bromley

Custom event-based solution

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

Here is another approach that hasn't been mentioned by the others here (as of this writing).

这是此处其他人未提及的另一种方法(在撰写本文时)。

You can use custom events like so:

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

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

This approach has the advantage of not requiring extra services to be written and then injected into every controller that needs to set the title, and also doesn't (ab)use the $rootScope. It also allows you to set a dynamic title (as in the code example), which is not possible using custom data attributes on the router's config object (as far as I know at least).

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