วิธีการเปลี่ยนส่วนหัวแบบไดนามิกตามมุมมองบางส่วนของ AngularJS ได้อย่างไร


411

ฉันใช้มุมมอง ng เพื่อรวมมุมมองบางส่วนของ 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สิ่งนี้มีประโยชน์สำหรับชุด metas แบบไดนามิก คุณเพิ่งจะเปลี่ยนตัวแปรเมตา $ rootScope ของคุณ
Kamuran Sönecek

คำตอบ:


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

Inject Pageและ Call 'Page.setTitle ()' จากคอนโทรลเลอร์

นี่คือตัวอย่างที่เป็นรูปธรรม: http://plnkr.co/edit/0e7T6l


11
อืมมมม ... ฉันไม่แน่ใจว่าการวางบริการตรงเข้าไปในขอบเขต $ ถือว่าดีในสถาปัตยกรรม AngularJS หรือไม่ อาจเป็นการดีกว่าถ้าคุณใส่ฟังก์ชัน $ Controller ไว้ในขอบเขตแล้วให้ฟังก์ชันนี้สอบถามบริการ
superjos

11
ตัวอย่างนี้ยอดเยี่ยมมาก ฉันมีหนึ่งการติดตาม แต่ในการโหลดครั้งแรกคุณสามารถเห็นข้อความ {{Page.title ()}} ในชื่อ (เร็วมาก) ฉันไม่คิดว่าคุณสามารถใช้เสื้อคลุมได้เพราะมันไม่ได้อยู่ในร่างกาย ข้อเสนอแนะใด ๆ เพื่อหลีกเลี่ยงปัญหานี้?
Arthur Frankel

52
@ArthurFrankel เพียงใช้ ng-bind (เช่น ng-bind = "Page.title ()")
Pius Uzamere

2
หรือเราสามารถระบุคอนโทรลเลอร์ในแท็ก title ไม่ต้องใช้คอนโทรลเลอร์ทั่วโลกบนส่วนหัว html: <title ng-controller = "titleCtrl"> {{Page.title ()}} </title>
Dmitri Algazin

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ททริบิวแทนการรักษา{{}}เพื่อไม่ให้โหลด


11
ถูกต้อง แต่ตัวอย่างของคุณไม่แสดงวิธีเปลี่ยนชื่อเรื่องใน $ routeChangeSuccess ที่กำหนดพารามิเตอร์โดยตัวแปร $ scope ซึ่งเป็นตัวอย่างของ @ tosh ที่ใช้บริการเพจ เพื่อให้คุณสามารถตั้งค่าแต่ไม่title = "Blog" title = '{{"Blog post " + post.title}}'
Eric Drechsel

10
@felix คุณสามารถเข้าถึงชื่อเหมือนcurrent.titleยัง
Eldelshell

8
$ rootScope.title = ปัจจุบัน $ route.title; ไม่มี
เบล่

7
ฉันเพิ่งอัพเกรดรุ่น Angular ของฉันหลายรุ่น (1.0.5 เป็น 1.2.7) และนี่ทำให้ฉันแตกหักในรหัสของฉัน ฉันใช้current.$routeรหัสเดิมและใช้งานได้ ด้วยการอัพเกรดจำเป็นต้องใช้ double $ on route current.$$route
Tyler Forsythe

6
ใน answser '/Product/:id'เมื่อสามารถดู มีวิธีที่จะมี:idค่าด้วยวิธีนี้หรือไม่? ฉันพยายามtitle: function(params){return params.id;}แต่ไม่ทำงาน ... อาจจะใช้resolve?
mickaelb91

190

โปรดทราบว่าคุณยังสามารถตั้งชื่อด้วย javascript โดยตรงเช่น

$window.document.title = someTitleYouCreated;

นี้ไม่ได้มีข้อมูลที่มีผลผูกพัน แต่มันพอเพียงเมื่อวางng-appใน<html>แท็กเป็นปัญหา (ตัวอย่างเช่นการใช้เทมเพลต JSP ที่<head>กำหนดไว้ในที่เดียว แต่คุณมีมากกว่าหนึ่งแอพ)


5
นี่เป็นวิธีเดียวที่จะทำให้ Internet Explorer ทำงานได้สำหรับฉันวิธีอื่น ๆ นั้นใช้งานได้กับเบราว์เซอร์อื่น ๆ
Maarten

4
อย่างที่มาร์ตินกล่าวถึงนี่เป็นวิธีการเดียวที่ทำงานใน ie7 และ ie8
rob

33
น่าอัศจรรย์ที่ผู้คนไม่สามารถถอยกลับและดูว่าสิ่งนี้สามารถทำได้ง่ายเพียงใดโดยไม่มีขอบเขตและโรงงาน
Redben

7
เหลือเชื่อ. นี่เป็นเรื่องที่ง่ายกว่าคนอื่น ๆ ขอบคุณ!
Leonard Teo

8
การใช้ 'หน้าต่าง' ธรรมดาเป็นเรื่องปกติ - นั่นทำหน้าที่โดยตรงบน DOM '$ window' เป็นสิ่งเชิงมุมและคุณต้องฉีดมันเพื่อใช้งาน จะใช้วิธีใดก็ได้
broc.seib

119

ประกาศng-appในhtmlองค์ประกอบให้ขอบเขตรากทั้งในและheadbody

ดังนั้นในคอนโทรลเลอร์ของคุณจะฉีด$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 ดังที่อธิบายไว้ในคำตอบที่ยอมรับนั้นไม่มีประโยชน์ในกรณีนี้
Nicolas Janel

1
ฉันรักวิธีที่มีน้ำหนักเบาแก้ปัญหานี้และจะหลีกเลี่ยงการใช้ $$ คุณสมบัติ
tedwards947

คำตอบที่ได้รับการยอมรับช่วยเพิ่มความยุ่งยากและความเสี่ยงที่ไม่จำเป็น รุ่นนี้ทำให้มันง่ายเหมือนการตั้งค่าตัวแปร
special0ne

3
หากคุณไม่ได้ตั้งค่าโดยใช้ $ rootScope ฉันอย่างน้อยที่สุดฉันจะแยกข้อมูลนี้ออกจากบริการดังนั้นคุณจึงไม่มี $ rootScope ในตัวควบคุมของคุณ
Michael J. Calkins

3
ฉันต้องการใช้วิธีแก้ปัญหานี้ แต่ฉันอยากรู้ว่าข้อดีของการใช้มันคือdocument.title = "App"อะไร
remarsh

43

โมดูลangularjs-viewheadแสดงกลไกในการตั้งชื่อตามมุมมองต่อการใช้คำสั่งที่กำหนดเองเท่านั้น

สามารถนำไปใช้กับองค์ประกอบมุมมองที่มีอยู่ซึ่งเนื้อหามีชื่อมุมมองอยู่แล้ว:

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

... หรือสามารถใช้เป็นองค์ประกอบแบบสแตนด์อโลนซึ่งในกรณีนี้องค์ประกอบจะไม่ปรากฏในเอกสารที่แสดงผลและจะใช้เพื่อตั้งค่าชื่อมุมมองเท่านั้น:

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

เนื้อหาของคำสั่งนี้มีให้ในขอบเขตรูviewTitleตดังนั้นจึงสามารถใช้กับอิลิเมนต์หัวเรื่องเหมือนกับตัวแปรอื่น ๆ :

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

นอกจากนี้ยังสามารถใช้ในจุดอื่น ๆ ที่สามารถ "ดู" ขอบเขตของรูทได้ ตัวอย่างเช่น:

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

วิธีนี้ช่วยให้สามารถตั้งชื่อได้ผ่านกลไกเดียวกับที่ใช้ควบคุมส่วนที่เหลือของงานนำเสนอ: เทมเพลต AngularJS สิ่งนี้หลีกเลี่ยงความจำเป็นในการถ่วงของตัวควบคุมด้วยตรรกะการนำเสนอนี้ คอนโทรลเลอร์ต้องการให้มีข้อมูลใด ๆ ที่จะใช้เพื่อแจ้งชื่อเรื่อง แต่เทมเพลตทำการกำหนดขั้นสุดท้ายเกี่ยวกับวิธีการนำเสนอและสามารถใช้การแก้ไขนิพจน์และตัวกรองเพื่อผูกข้อมูลขอบเขตตามปกติ

(ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้เขียนโมดูลนี้ แต่ฉันอ้างอิงที่นี่โดยหวังว่ามันจะช่วยคนอื่นในการแก้ปัญหานี้)


4
ไม่อยากเชื่อเลยว่าโซลูชันนี้ยังไม่ได้รับการโหวตเพิ่มอีก ส่วนใหญ่เป็นตัวเลือกการออกแบบที่ไม่ดีจริงๆ
Martin Wawrusch

เห็นด้วยนี่ควรจะเป็นทางออกที่ดีที่สุด ฉันชอบสิ่งนี้ดีกว่าการประกาศตัวควบคุมที่ระดับหน้าเพื่อตั้งชื่อ FYI: การใช้สิ่งนี้กับ Angular v1.3.2 และ angular-route-segment v1.3.3 และมันใช้งานได้อย่างมีเสน่ห์
Nate Barbettini

ฉันรับรองโซลูชันนี้)
jkoreska

3
ฉันเขียนเพิ่มเติมเกี่ยวกับ angularjs-viewhead และแนวคิดอื่นที่เกี่ยวข้องที่นี่ในบล็อกของฉัน: apparently.me.uk/angularjs-view-specific-sidebars
Martin Atkins

หากการใช้มุมมองเดียวกันซ้ำที่มุมมองระดับบนสุดและที่มุมมองย่อยคุณสามารถใช้มุมมองหัวเรื่องด้วย ng-if เช่น: <h4 ng-if = "$ state.includes ('some-state')" view-title> รายละเอียดสำหรับ {{... }} </h4> <h4 ng-if = "! $ state.includes ('some-state')"> รายละเอียดสำหรับ {{... }} </ h4 >
ANRE

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' ปลอดภัยกว่าในเรื่องนี้
Kristo Aun

@ 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';
Henrik Stenbæk

ฉันได้รับข้อผิดพลาดที่ไม่ได้กำหนดดังนั้นฉันจึงเปลี่ยนบิตสุดท้ายเป็น: $ rootScope.page.title = current เส้นทาง $$? ปัจจุบัน $$ route.title + '| ชื่อเว็บไซต์ ':' ชื่อเว็บไซต์ ';
Andy

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

ปัญหาเล็ก ๆ เมื่อคุณรีเฟรชหน้าในชื่อแท็บของคุณคุณเห็น '{{title}}' และหลังจากที่แสดงหน้าแล้วคุณจะเห็น 'บางชื่อ' เท่านั้น วิธีการแก้ปัญหากับโรงงานไม่มีพฤติกรรมนั้น
Dmitri Algazin

5
{{title}}ใช้แทนng-bind='title'
Faradox

1
เห็นด้วยกับ @Faradox ... การใช้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-routerURL ที่ปรับปรุงและเนื้อหาที่อยู่บนพื้นฐานของรัฐของฉันและฉันไม่ได้รับข้อผิดพลาดหรือคำเตือน แต่ฉันไม่สามารถดูเหมือนจะเข้าถึงเป็นส่วนหนึ่งของวัตถุที่รัฐกำหนดค่าใด ๆ $state.current.[...]ผ่านทาง คุณใช้เวอร์ชันui-routerนี้ทำอะไร

การแก้ไข "Runtime Config" ของฉันในคำตอบช่วยแก้ปัญหาที่ฉันกล่าวถึงในความคิดเห็นของฉันด้านบน :) ฉันเปิดรับแนวคิดหากมีวิธีที่ดีกว่าในการทำเช่นนี้

สิ่งนี้ไม่ได้ผลสำหรับฉันและไม่พบ 'ชื่อ' ในเอกสาร 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ใช้ นอกจากนี้ยังช่วยให้คุณสามารถตั้งชื่อแบบไดนามิก (เช่นในตัวอย่างรหัส) ซึ่งไม่สามารถทำได้โดยใช้แอตทริบิวต์ข้อมูลที่กำหนดเองบนวัตถุ config ของเราเตอร์ (เท่าที่ฉันรู้อย่างน้อย)


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/


5

หากคุณไม่สามารถควบคุมองค์ประกอบของหัวเรื่อง (เช่นเว็บฟอร์ม 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;
        });
    });

4

วิธีที่ง่ายและสกปรกโดยใช้$rootScope:

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

ในตัวควบคุมของคุณเมื่อคุณมีข้อมูลที่จำเป็นในการสร้างชื่อให้ทำ:

$rootScope.title = 'Page X'

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ว่าคอนโทรลเลอร์ใดที่มีแท็กชื่อเรื่องที่กำหนดเองอยู่ในขณะนี้

ตรวจสอบให้แน่ใจว่าคุณไม่มีแท็กชื่อหน้าหลายแท็กในหน้าของคุณ

Plunker ตัวอย่างที่นี่http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV คุณจะต้องดาวน์โหลดรหัสไปรษณีย์และเรียกใช้ในเครื่องเพื่อดูการเปลี่ยนชื่อ


ฉันมากับสิ่งที่คล้ายกัน 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);
   });
}]);

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 สำหรับ partials ของฉัน:

<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 [ซ้ำซากรู้ - อาจเป็นไซต์ที่ฉลองนักเก็ตไก่ทุกชนิด;) อย่างไรก็ตามคุณสามารถอัปเดตชื่อเมื่อผู้ใช้คลิกที่ลิงก์ใด ๆ ดังนั้นในหน้าหลักของ Critters 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 docs ล้าสมัยและแสดงเวอร์ชัน 0.9 ของ ng-bind-template คุณจะเห็นว่ามันไม่แตกต่างกันมาก

หลังจากนั้น: คุณรู้สิ่งนี้ แต่มันมีไว้สำหรับคนอื่น ที่ด้านล่างของ index.html ต้องมี app.js พร้อมโมดูล:

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

2
ความคิดเห็นของฉันอย่าใช้สิ่งนี้ คุณกำลังผสมข้อมูล (ข้อมูล) ในมุมมอง (การนำเสนอ) หลังจากนั้นมันจะยากมากที่จะหาแหล่งที่มาของชื่อเรื่องกระจัดกระจายไปทั่วลิงก์ HTML ของคุณที่อาจมีอยู่ในสถานที่ต่าง ๆ ในมุมมอง ..
amit bakle

เนื่องจากชื่อเรื่องได้รับการอัปเดตเมื่อคลิกที่ลิงก์จริงเท่านั้นจึงไม่ได้ตั้งชื่ออย่างถูกต้องเมื่อผู้ใช้เข้าสู่หน้าแรกหรือเมื่อผู้ใช้รีเฟรช
Mark Amery

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

โซลูชันที่อิงตามเหตุการณ์ที่กำหนดเองได้รับแรงบันดาลใจจากMichael Bromley

ฉันไม่สามารถใช้งานได้กับ $ 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-binding เข้ากับแท็กชื่อ

ตัวควบคุมตัวอย่าง:

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

อีกครั้งผู้อื่นอาจมีแนวคิดที่ดีกว่าเกี่ยวกับวิธีการเข้าถึงสิ่งนี้ แต่เนื่องจากฉันใช้การแสดงผลล่วงหน้าความต้องการของฉันจึงได้รับการตอบสนอง


0

ขอบคุณtosh shimayamaสำหรับวิธีแก้ปัญหาของเขา
ฉันคิดว่ามันไม่สะอาดนักที่จะนำบริการไปใช้โดยตรง$scopeดังนั้นนี่คือความแตกต่างเล็กน้อยของฉัน: http://plnkr.co/edit/QJbuZZnZEDOBcYrJXWWs

คอนโทรลเลอร์ (ซึ่งในคำตอบเดิมดูเหมือนว่าฉันจะโง่เกินไปนิดหน่อย) สร้างวัตถุ ActionBar และอันนี้ยัดเข้าไปในขอบเขต $
วัตถุรับผิดชอบการสอบถามบริการจริง ๆ นอกจากนี้ยังซ่อนจาก $ ขอบเขตการโทรเพื่อตั้งค่าเทมเพลต URL ซึ่งผู้ควบคุมรายอื่นสามารถตั้งค่า URL แทนได้


0

Mr Hashมีคำตอบที่ดีที่สุด แต่วิธีการแก้ปัญหาด้านล่างทำให้เหมาะ (สำหรับฉัน) โดยการเพิ่มประโยชน์ดังต่อไปนี้:

  • เพิ่มไม่มีนาฬิกาซึ่งสามารถทำให้ช้าลง
  • จริงๆแล้วสิ่งที่ฉันอาจทำในตัวควบคุมโดยอัตโนมัติจริง ๆ แล้ว
  • ยังให้สิทธิ์การเข้าถึงจากคอนโทรลเลอร์หากฉันยังต้องการ
  • ไม่มีการฉีดเสริม

ในเราเตอร์:

  .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 เพื่อติดตามการเปลี่ยนแปลงตัวแปรแล้วอัปเดตชื่อ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.