javascript - AngularJS आंशिक दृश्य के आधार पर शीर्षलेख को गतिशील रूप से कैसे बदलें?




templates partial-views (14)

मैं AngularJS आंशिक विचारों को शामिल करने के लिए एनजी-व्यू का उपयोग कर रहा हूं, और मैं शामिल दृश्य के आधार पर पेज शीर्षक और एच 1 हेडर टैग अपडेट करना चाहता हूं। ये आंशिक दृश्य नियंत्रकों के दायरे से बाहर हैं, और इसलिए मैं यह नहीं समझ सकता कि उन्हें नियंत्रकों में डेटा सेट से कैसे बांधना है।

अगर यह एएसपी.नेट एमवीसी था तो आप इसे करने के लिए @ViewBag का उपयोग कर सकते हैं, लेकिन मुझे AngularJS में समकक्ष नहीं पता है। मैंने साझा सेवाओं, घटनाओं आदि के बारे में खोज की है लेकिन अभी भी यह काम नहीं कर पा रहा है। मेरे उदाहरण को संशोधित करने का कोई भी तरीका इसलिए यह काम करता है बहुत सराहना की जाएगी।

मेरा एचटीएमएल:

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

मेरी जावास्क्रिप्ट:

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

कस्टम घटना-आधारित समाधान

यहां एक और दृष्टिकोण है जिसका उल्लेख दूसरों द्वारा नहीं किया गया है (इस लेखन के रूप में)।

आप कस्टम इवेंट्स का उपयोग इस प्रकार कर सकते हैं:

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

इस दृष्टिकोण का लाभ उठाने के लिए अतिरिक्त सेवाओं की आवश्यकता नहीं है और फिर शीर्षक को सेट करने के लिए आवश्यक प्रत्येक नियंत्रक में इंजेक्शन दिया गया है, और यह भी नहीं (एबी) $rootScope उपयोग नहीं करता है। यह आपको गतिशील शीर्षक (कोड उदाहरण के रूप में) सेट करने की अनुमति देता है, जो राउटर की कॉन्फ़िगर ऑब्जेक्ट (जहां तक ​​मुझे कम से कम पता है) पर कस्टम डेटा विशेषताओं का उपयोग करना संभव नहीं है।


jkoreska का समाधान सही है यदि आप हाथ से पहले शीर्षक जानते हैं, लेकिन आपको संसाधन से प्राप्त डेटा के आधार पर शीर्षक सेट करने की आवश्यकता हो सकती है।

मेरे समाधान के लिए एक ही सेवा की आवश्यकता है। चूंकि रूटस्कोप सभी डीओएम तत्वों का आधार है, इसलिए हमें एचटीएमएल तत्व पर नियंत्रक डालने की आवश्यकता नहीं है

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

आप नियंत्रक को <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 }
   };
});

नियंत्रक से Page और कॉल 'Page.setTitle ()' इंजेक्ट करें।

यहां ठोस उदाहरण है: http://plnkr.co/edit/0e7T6l


इनमें से कोई भी जवाब पर्याप्त सहज नहीं था, इसलिए मैंने ऐसा करने के लिए एक छोटा सा निर्देश बनाया। इस तरह से आप पृष्ठ में शीर्षक घोषित कर सकते हैं, जहां कोई सामान्य रूप से ऐसा करता है, और इसे गतिशील भी होने देता है।

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>

वैकल्पिक रूप से, आप इसे अधिक आईई-फ्रेंडली बनाने के लिए एक विशेषता का उपयोग कर सकते हैं:

<div page-title>Title: {{titleText}}</div>

आप कोणीय कोड सहित, पाठ्यक्रम के टैग में जो भी पाठ चाहते हैं उसे डाल सकते हैं। इस उदाहरण में, यह कस्टम-शीर्षक टैग वर्तमान में मौजूद नियंत्रक में $scope.titleText तलाश करेगा।

बस सुनिश्चित करें कि आपके पृष्ठ पर एकाधिक पृष्ठ-शीर्षक टैग नहीं हैं, या वे एक-दूसरे को पकड़ लेंगे।

यहां प्लंकर उदाहरण http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV । शीर्षक परिवर्तन देखने के लिए आपको ज़िप डाउनलोड करना होगा और इसे स्थानीय रूप से चलाने होंगे।


का अब तक का सबसे अच्छा जवाब था, लेकिन नीचे दिए गए समाधान में निम्नलिखित लाभ जोड़कर यह आदर्श (मेरे लिए) बनाता है:

  • कोई घड़ियों नहीं जोड़ता है, जो चीजों को धीमा कर सकता है
  • असल में स्वचालित रूप से स्वचालित करता है जो मैंने नियंत्रक में किया हो, अभी तक
  • अगर मैं अभी भी इसे चाहता हूं तो भी मुझे नियंत्रक से पहुंच प्रदान करता है।
  • कोई अतिरिक्त इंजेक्शन नहीं

राउटर में:

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

कोणीय-यूई-राउटर के लिए सरल समाधान:

एचटीएमएल:

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

जबकि अन्य के पास बेहतर तरीके हो सकते हैं, मैं अपने नियंत्रकों में $ रूटस्कोप का उपयोग करने में सक्षम था, क्योंकि मेरे प्रत्येक दृश्य / टेम्पलेट्स में एक अलग नियंत्रक है। आपको प्रत्येक नियंत्रक में $ rootScope इंजेक्ट करने की आवश्यकता होगी। हालांकि यह आदर्श नहीं हो सकता है, यह मेरे लिए काम कर रहा है, इसलिए मैंने सोचा कि मुझे इसे पास करना चाहिए। यदि आप पृष्ठ का निरीक्षण करते हैं, तो यह शीर्षक टैग पर एनजी-बाइंडिंग जोड़ता है।

उदाहरण नियंत्रक:

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>

आप पेजटाइट और पृष्ठ डिस्क्रिप्शन को डायनामिक मानों पर भी सेट कर सकते हैं, जैसे कि आरईएसटी कॉल से डेटा लौटाना:

    $scope.article = restCallSingleArticle.get({ articleID: $routeParams.articleID }, function() {
    // Dynamic Page Title and Description
    $rootScope.pageTitle = $scope.article.articletitle;
    $rootScope.pageDescription = $scope.article.articledescription;
});

दोबारा, दूसरों के पास इस दृष्टिकोण के बारे में बेहतर विचार हो सकते हैं, लेकिन चूंकि मैं प्री-रेन्डरिंग का उपयोग कर रहा हूं, मेरी ज़रूरतें पूरी की जा रही हैं।


ध्यान दें कि आप शीर्षक को सीधे जावास्क्रिप्ट के साथ भी सेट कर सकते हैं, यानी,

$window.document.title = someTitleYouCreated;

इसमें डेटा बाध्यकारी नहीं है, लेकिन <html> टैग में ng-app डालने पर यह समस्याग्रस्त है। (उदाहरण के लिए, जेएसपी टेम्पलेट्स का उपयोग करना जहां <head> को एक ही स्थान पर परिभाषित किया गया है, फिर भी आपके पास एक से अधिक ऐप हैं।)


मैंने पाया है कि बेहतर और गतिशील समाधान वैरिएबल परिवर्तनों का पता लगाने के लिए $ घड़ी का उपयोग करना है और फिर शीर्षक को अपडेट करना है।


मॉड्यूल angularjs-viewhead केवल एक कस्टम निर्देश का उपयोग करके प्रति-दृश्य आधार पर शीर्षक सेट करने के लिए एक तंत्र दिखाता है।

इसे या तो मौजूदा दृश्य तत्व पर लागू किया जा सकता है जिसका सामग्री पहले से ही दृश्य शीर्षक है:

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

... या इसे एक स्टैंडअलोन तत्व के रूप में उपयोग किया जा सकता है, इस मामले में तत्व प्रस्तुत दस्तावेज़ में अदृश्य हो जाएगा और केवल दृश्य शीर्षक सेट करने के लिए उपयोग किया जाएगा:

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

इस निर्देश की सामग्री रूट स्कोप में viewTitle रूप में उपलब्ध viewTitle , इसलिए इसे किसी अन्य चर की तरह शीर्षक तत्व पर भी उपयोग किया जा सकता है:

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

इसका उपयोग किसी अन्य स्थान पर भी किया जा सकता है जो रूट स्कोप को "देख" सकता है। उदाहरण के लिए:

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

यह समाधान शीर्षक को उसी तंत्र के माध्यम से सेट करने की अनुमति देता है जिसका उपयोग बाकी प्रस्तुति को नियंत्रित करने के लिए किया जाता है: AngularJS टेम्पलेट्स। यह इस प्रस्तुति तर्क के साथ अव्यवस्था नियंत्रकों की आवश्यकता से बचाता है। नियंत्रक को किसी भी डेटा को उपलब्ध कराने की आवश्यकता होती है जिसका उपयोग शीर्षक को सूचित करने के लिए किया जाएगा, लेकिन टेम्पलेट इसे प्रस्तुत करने के तरीके पर अंतिम निर्धारण करता है, और अभिव्यक्ति इंटरपोलेशन और फ़िल्टर का उपयोग सामान्य रूप से डेटा को स्कैन करने के लिए कर सकता है।

(अस्वीकरण: मैं इस मॉड्यूल का लेखक हूं, लेकिन मैं इसे केवल उम्मीद में संदर्भित कर रहा हूं कि यह किसी और को इस समस्या को हल करने में मदद करेगा।)


यदि आपके पास शीर्षक तत्व (जैसे एएसपीनेट वेब फॉर्म) पर नियंत्रण नहीं है तो यहां कुछ चीज है जिसका आप उपयोग कर सकते हैं

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

शीर्षक परिवर्तन करने का एक अलग तरीका यहां दिया गया है। हो सकता है कि फैक्ट्री फ़ंक्शन के रूप में स्केलेबल न हो (जो असीमित पृष्ठों को संभाल सकता है) लेकिन मेरे लिए यह समझना आसान था:

मेरे 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 का उपयोग करके nav.html जोड़ा और मेरे आंशिक के लिए ng-view जोड़ा:

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

}());

यदि आप मॉड्यूल के अंत की ओर देखते हैं, तो आप देखेंगे कि मेरे पास एक क्रेटर-विवरण पृष्ठ है: आईडी। यह एक आंशिक है जो क्रिस्पी क्रिटर्स पेज से उपयोग किया जाता है। [कॉर्न, मुझे पता है - शायद यह एक ऐसी साइट है जो सभी प्रकार के चिकन नगेट्स मनाती है;) वैसे भी, जब आप किसी भी लिंक पर क्लिक करते हैं तो आप शीर्षक को अपडेट कर सकते हैं, इसलिए मेरे मुख्य क्रिस्पी क्रिटर्स पेज में जो क्रिटर-विवरण पृष्ठ की ओर जाता है, यही वह जगह है जहां $ 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 दस्तावेज़ों में उदाहरण पृष्ठ पुराना है और ng-bind-template का 0.9 संस्करण दिखाता है। आप देख सकते हैं कि यह इतना अलग नहीं है।

बाद में विचार: आप इसे जानते हैं लेकिन यह किसी और के लिए यहां है; index.html के नीचे, मॉड्यूल के साथ app.js को शामिल करना होगा:

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

$rootScope का उपयोग कर सरल और गंदे तरीके:

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

आपके नियंत्रकों में, जब आपके पास शीर्षक बनाने के लिए आवश्यक डेटा होता है, तो करें:

$rootScope.title = 'Page X'






angular-routing