javascript - this angular js




Come modificare dinamicamente l'intestazione in base alla vista parziale di AngularJS? (15)

Soluzione basata su eventi personalizzati

Ecco un altro approccio che non è stato menzionato dagli altri qui (al momento in cui scrivo).

Puoi usare eventi personalizzati in questo modo:

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

Questo approccio ha il vantaggio di non richiedere servizi aggiuntivi da scrivere e quindi iniettare in ogni controller che deve impostare il titolo, e inoltre (ab) non usa $rootScope . Consente inoltre di impostare un titolo dinamico (come nell'esempio di codice), che non è possibile utilizzando gli attributi dei dati personalizzati sull'oggetto config del router (per quanto ne so almeno).

Sto usando ng-view per includere le viste parziali di AngularJS e voglio aggiornare il titolo della pagina e i tag di intestazione h1 in base alla vista inclusa. Tuttavia, questi sono fuori dall'ambito dei controller delle viste parziali e quindi non riesco a capire come associarli al set di dati nei controller.

Se fosse ASP.NET MVC, puoi usare @ViewBag per farlo, ma non conosco l'equivalente in AngularJS. Ho cercato servizi condivisi, eventi, ecc. Ma non riesco ancora a farlo funzionare. Un modo per modificare il mio esempio in modo che funzioni sarebbe molto apprezzato.

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

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

Soluzione personalizzata basata su eventi ispirata a Michael Bromley

Non ero in grado di farlo funzionare con $ scope, quindi ho provato con rootScope, forse un po 'più sporco ... (specialmente se si effettua un aggiornamento sulla pagina che non registra l'evento)

Ma mi piace molto l'idea di come le cose siano liberamente accoppiate.

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

Funziona per me :)


Ecco un modo diverso di fare modifiche al titolo. Forse non è scalabile come una funzione di fabbrica (che potrebbe concepibilmente gestire pagine illimitate), ma è stato più facile per me capire:

Nel mio index.html ho iniziato così:

    <!DOCTYPE html>
      <html ng-app="app">
        <head>
          <title ng-bind-template="{{title}}">Generic Title That You'll Never See</title>

Quindi ho creato un partial chiamato "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>

Poi sono tornato a "index.html" e ho aggiunto il nav.html usando ng-include e la ng-view per i miei partial:

<body class="ng-cloak" ng-controller="MainCtrl">
    <div ng-include="'partials/nav.html'"></div>
    <div>
        <div ng-view></div>
    </div>

Si noti che ng-cloak? Non ha nulla a che fare con questa risposta, ma nasconde la pagina fino al completamento del caricamento, un bel tocco :) Scopri come: Angularjs - ng-cloak / ng-mostra gli elementi lampeggiano

Ecco il modulo di base. L'ho messo in un file chiamato "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"});
    });

}());

Se guardi verso la fine del modulo, vedrai che ho una pagina di critter-detail basata su: id. È parziale utilizzato dalla pagina Crispy Critters. [Corny, lo so - forse è un sito che celebra tutti i tipi di pepite di pollo;) Ad ogni modo, è possibile aggiornare il titolo quando un utente fa clic su qualsiasi link, quindi nella mia pagina principale Crispy Critters che porta alla pagina dei dettagli critici, è lì che andrà l'aggiornamento $ root.title, proprio come hai visto nel nav.html sopra:

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

Mi dispiace così tanto, ma preferisco un post che dia abbastanza dettagli per farlo funzionare. Si noti che la pagina di esempio nei documenti di AngularJS non è aggiornata e mostra una versione 0.9 di ng-bind-template. Puoi vedere che non è molto diverso.

Ripensamento: lo sai ma è qui per chiunque altro; nella parte inferiore dell'indice.html, è necessario includere l'app.js con il modulo:

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

Ecco una soluzione adattata che funziona per me che non richiede l'iniezione di $ rootScope nei controller per l'impostazione di titoli di pagina specifici delle risorse.

Nel modello principale:

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

Nella configurazione di routing:

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

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

E nel blocco di corsa:

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

Finalmente nel controller:

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

Ho appena scoperto un buon modo per impostare il titolo della tua pagina se stai utilizzando il routing:

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

Modifica : usando l'attributo ng-bind invece di curlies {{}} modo che non vengano visualizzati al caricamento


Il modulo angularjs-viewhead mostra un meccanismo per impostare il titolo su una vista per visualizzazione usando solo una direttiva personalizzata.

Può essere applicato a un elemento vista esistente il cui contenuto è già il titolo della vista:

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

... o può essere usato come elemento autonomo, nel qual caso l'elemento sarà invisibile nel documento reso e sarà usato solo per impostare il titolo della vista:

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

Il contenuto di questa direttiva è reso disponibile viewTitle base come viewTitle , quindi può essere utilizzato sull'elemento title come qualsiasi altra variabile:

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

Può anche essere utilizzato in qualsiasi altro punto in grado di "vedere" l'ambito di root. Per esempio:

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

Questa soluzione consente di impostare il titolo tramite lo stesso meccanismo utilizzato per controllare il resto della presentazione: modelli AngularJS. Ciò evita la necessità di ingombrare i controller con questa logica di presentazione. Il controller deve rendere disponibili tutti i dati che verranno utilizzati per informare il titolo, ma il modello stabilisce la decisione finale su come presentarlo e può utilizzare l'interpolazione delle espressioni e i filtri per eseguire il binding ai dati dell'oscilloscopio come di consueto.

(Disclaimer: io sono l'autore di questo modulo, ma sto facendo riferimento qui solo nella speranza che possa aiutare qualcun altro a risolvere questo problema.)


La dichiarazione di ng-app sull'elemento html fornisce l'ambito radice sia per la head che per il body .

Pertanto nel controller inietta $rootScope e imposta una proprietà di intestazione su questo:

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

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

e nella tua pagina:

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

La soluzione di jkoreska è perfetta se conosci i titoli in anticipo, ma potresti dover impostare il titolo in base ai dati ottenuti da una risorsa, ecc.

La mia soluzione richiede un singolo servizio. Poiché rootScope è la base di tutti gli elementi DOM, non è necessario mettere un controller sull'elemento html come qualcuno menzionato

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')
// ...

Tutti i controller che devono cambiare titolo

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

Mentre altri potrebbero avere metodi migliori, sono stato in grado di utilizzare $ rootScope nei miei controller, poiché ciascuna delle mie viste / modelli ha un controller distinto. Sarà necessario iniettare $ rootScope in ogni controller. Anche se questo potrebbe non essere l'ideale, funziona per me, quindi ho pensato di doverlo passare. Se ispezionate la pagina, aggiunge il ng-binding al tag del titolo.

Controller di esempio:

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

Esempio di intestazione 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>

Puoi anche impostare il titolo della pagina e la descrizione della pagina su valori dinamici, come la restituzione di dati da una chiamata REST:

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

Di nuovo, altri potrebbero avere idee migliori su come affrontarlo, ma dal momento che sto usando un pre-rendering, i miei bisogni vengono soddisfatti.


Modo semplice e sporco usando $rootScope :

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

Nei tuoi controllori, quando hai i dati necessari per creare il titolo, fai:

$rootScope.title = 'Page X'

Nota che puoi anche impostare il titolo direttamente con javascript, cioè,

$window.document.title = someTitleYouCreated;

Questo non ha l'associazione dei dati, ma è sufficiente quando inserire ng-app nel tag <html> è problematico. (Ad esempio, utilizzando i modelli JSP dove <head> è definito esattamente in un punto, ma hai più di un'app.)


Per gli scenari in cui non si dispone di una ngApp che contiene il tag title , è sufficiente iniettare un servizio ai controller che devono impostare il titolo della finestra.

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

Esempio di lavoro ... http://jsfiddle.net/8m379/1/


Se non hai il controllo sull'elemento title (come il modulo web asp.net) ecco alcune cose che puoi usare

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

Soluzione semplicistica per angolari-ui-router:

HTML:

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

App.js> blocco 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);
   });
}]);

avuto la risposta migliore fino ad ora, ma la soluzione seguente lo rende ideale (per me) aggiungendo i seguenti vantaggi:

  • Non aggiunge orologi, che possono rallentare le cose
  • Effettivamente automatizza ciò che avrei potuto fare nel controller, ancora
  • Ancora mi dà accesso dal controller se lo voglio ancora.
  • Nessuna iniezione extra

Nel router:

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

Nel blocco di corsa:

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




angular-routing