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

IT技术 javascript angularjs templates partial-views angular-routing
2021-02-01 13:42:56

我正在使用 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"; }
6个回答

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

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属性而不是curl,{{}}这样它们就不会在加载时显示

我刚刚将我的 Angular 版本升级了几个版本(1.0.5 到 1.2.7),这让我在我的代码中崩溃了。current.$route在旧代码中使用它并且它正在工作。升级后,需要在路由上加双 $。current.$$route
2021-03-23 13:42:56
是的,但是您的示例没有显示如何更改由 $scope 变量参数化的 $routeChangeSuccess 上的标题,@tosh 使用 Page 服务的示例就是这样做的。所以你可以设置title = "Blog"但不能title = '{{"Blog post " + post.title}}'
2021-04-05 13:42:56
在回答的时候可以看到'/Product/:id'有没有办法:id用这种方法获得value?我试过title: function(params){return params.id;}但没有用...也许使用resolve
2021-04-08 13:42:56
@felix你可以像访问标题current.title
2021-04-09 13:42:56
$rootScope.title = current.$route.title; 没有双重 $$
2021-04-10 13:42:56

您可以在<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

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

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

$window.document.title = someTitleYouCreated;

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

难以置信的。这比其他人提到的所有恶作剧要简单得多。谢谢!
2021-03-14 13:42:56
对我来说,这是让它在 Internet Explorer 上运行的唯一方法,但其他方法也适用于其他浏览器
2021-03-18 13:42:56
使用普通的“窗口”很好——直接作用于 DOM。'$window' 是一个有角度的东西,你必须注入它才能使用它。无论哪种方式都会起作用。
2021-03-23 13:42:56
正如 Maarten 所说,这是唯一适用于 ie7 和 ie8 的方法
2021-03-28 13:42:56
令人惊讶的是人们如何不能退后一步,看看没有范围和工厂可以轻松完成这件事
2021-04-03 13:42:56

ng-apphtml元素声明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>
我的意见的最佳答案。在这种情况下,在接受的答案中描述的 ng-app 级别的控制器是无用的。
2021-03-19 13:42:56
我想使用这个解决方案,但我很好奇使用它的好处是什么document.title = "App"
2021-04-02 13:42:56
接受的答案增加了不必要的复杂性和风险。这个版本使它像设置一个变量一样简单。
2021-04-05 13:42:56
如果您对使用 $rootScope 死心塌地,我至少会将其提取到服务中,这样您的控制器中就没有 $rootScope 。
2021-04-07 13:42:56
我喜欢这个解决方案的轻量级,它避免使用 $$ 属性
2021-04-10 13:42:56

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

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

我赞同这个解决方案;)
2021-03-17 13:42:56
如果在顶级和子级视图重用相同的视图,仍然可以使用带有 ng-if 的视图标题,例如:<h4 ng-if="$state.includes('some-state')" view-title>{{...}} 的详细信息</h4> <h4 ng-if="!$state.includes('some-state')">{{...}} 的详细信息</h4 >
2021-03-18 13:42:56
我在我的博客上写了更多关于 angularjs-viewhead 和另一个相关想法的内容:apparently.me.uk/angularjs-view-specific-sidebars
2021-03-21 13:42:56
不敢相信这个解决方案没有得到更多的支持。其他大多数都是非常糟糕的设计选择。
2021-04-01 13:42:56
同意,这应该是最佳解决方案。我喜欢这比在页面级别声明一个控制器来设置标题要好得多。仅供参考:将它与 Angular v1.3.2 和 angular-route-segment v1.3.3 一起使用,它就像一个魅力。
2021-04-05 13:42:56