AngularJSの部分ビューを含めるためにng-viewを使用しています。含まれているビューに基づいてページタイトルとh1ヘッダータグを更新します。ただし、これらは部分的なView Controllerの範囲外であるため、それらをController内のデータセットにバインドする方法を理解することはできません。
それが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"; }
<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
ルーティングを使用している場合にページタイトルを設定するための良い方法を発見しました。
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 — ' + title">myApp</title>
...
編集 :カーリーng-bind
の代わりに{{}}
属性を使用してロード時に表示されないようにする
Javascriptを使ってタイトルを直接設定することもできます。
$window.document.title = someTitleYouCreated;
これにはデータバインディングはありませんが、ng-app
タグに<html>
を入れることに問題がある場合は十分です。 (たとえば、<head>
が厳密に1か所で定義されているJSPテンプレートを使用していても、複数のアプリがあります。)
html
要素でng-app
を宣言すると、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>
モジュール angularjs-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テンプレートを使用してタイトルを設定できます。これにより、この表示ロジックでコントローラを雑然とさせる必要がなくなります。コントローラは inform 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);
}
jkoreskaの解決策は、事前にタイトルを知っていれば完璧ですが、リソースなどから得たデータに基づいてタイトルを設定する必要があるかもしれません。
私の解決策は単一のサービスを必要とします。 rootScopeはすべてのDOM要素の基盤であるため、他の人が言ったようにhtml要素にコントローラを配置する必要はありません。
app.service('Page', function($rootScope){
return {
setTitle: function(title){
$rootScope.title = title;
}
}
});
doctype html
html(ng-app='app')
head
title(ng-bind='title')
// ...
app.controller('SomeController', function(Page){
Page.setTitle("Some Title");
});
タイトルやメタ説明を動的に設定することを可能にするきれいな方法。例では私は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>
...
あるいは、 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.'
}
}
これは他の人によってここで言及されていない別のアプローチです(これを書いている時点で)。
あなたはそのようなカスタムイベントを使うことができます:
// 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
を使用しない(ab)という利点があります。 (コード例のように)動的なタイトルを設定することもできます。これは、(少なくとも私の知る限りでは)ルーターの設定オブジェクトにカスタムデータ属性を使用することはできません。
(asp.net Webフォームのように)title要素を制御できない場合は、ここで使用できるものがあります。
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;
});
});
title
タグを含むngAppがないシナリオでは、ウィンドウタイトルを設定する必要があるコントローラにサービスを注入するだけです。
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/ /
$rootScope
を使った簡単で汚い方法:
<html ng-app="project">
<head>
<title ng-bind="title">Placeholder title</title>
タイトルを作成するために必要なデータがある場合は、コントローラで次のようにします。
$rootScope.title = 'Page X'
これらの答えはどれも十分直感的に思えないので、私はこれを行うための小さなディレクティブを作成しました。この方法で、あなたがページでタイトルを宣言することを可能にします、そして、それは通常それをするでしょう、そしてそれは同様に動的であることを可能にします。
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>
Angular codeを含め、必要なテキストはもちろんタグに付けることができます。この例では、カスタムタイトルタグが現在入っているどのコントローラでも$scope.titleText
を探します。
あなたのページに複数のpage-titleタグがないことを確認してください。
ここでプランカーの例 http://plnkr.co/edit/nK63te7BSbCxLeZ2ADHV 。タイトルの変更を確認するには、Zipをダウンロードしてローカルで実行する必要があります。
これは、タイトルを変更する別の方法です。ファクトリ関数ほどはスケーラブルではないかもしれません(おそらく無制限のページを扱うことができるでしょう)が、私にとって理解しやすいものでした:
私の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とng-viewを使ってnav.htmlを追加しました。
<body class="ng-cloak" ng-controller="MainCtrl">
<div ng-include="'partials/nav.html'"></div>
<div>
<div ng-view></div>
</div>
そのng-cloak?この答えには関係ありませんが、読み込みが完了するまでページを非表示にします。いい感じ:)ここで説明します: Angularjs - ng-cloak/ng-show elements blink
これが基本的なモジュールです。それを "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ページから使用される部分的です。 [Corny、私は知っている - 多分それはあらゆる種類のチキンナゲットを祝うサイトである;)とにかく、ユーザーが任意のリンクをクリックしたときにタイトルを更新することができます。上記のnav.htmlで見たように、$ root.titleの更新が行われる場所です。
<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のドキュメントの例のページは古く、0.9バージョンのng-bind-templateを示しています。それほど変わらないことがわかります。
後付け:あなたはこれを知っていますが、それは他の誰にとってもここにあります。 index.htmlの一番下に、app.jsをモジュールと共に含める必要があります。
<!-- APP -->
<script type="text/javascript" src="js/app.js"></script>
</body>
</html>
アンギュラUIルーターのための単純化された解法:
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);
});
}]);
これを解決しなければならなかったとき、私はページのhtml
タグにng-app
を置くことができなかったので、私はサービスでそれを解決しました:
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;
}
};
});
$ 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>
それは私のために働いています:)
他の人がより良い方法を持っているかもしれませんが、私のそれぞれのビュー/テンプレートは別々のコントローラを持っているので、私は私のコントローラで$ rootScopeを使うことができました。各コントローラに$ rootScopeを挿入する必要があります。これは理想的ではないかもしれませんが、それは私のために機能しているので、私はそれを渡すべきだと思いました。ページを調べると、ng-bindingがtitleタグに追加されます。
コントローラの例:
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>
REST呼び出しからデータを返すなど、pageTitleおよびpageDescriptionを動的な値に設定することもできます。
$scope.article = restCallSingleArticle.get({ articleID: $routeParams.articleID }, function() {
// Dynamic Page Title and Description
$rootScope.pageTitle = $scope.article.articletitle;
$rootScope.pageDescription = $scope.article.articledescription;
});
繰り返しになりますが、他の人がこれにどう対処するかについてより良いアイデアを持っているかもしれませんが、私はプリレンダリングを使用しているので、私のニーズは満たされています。
ハッシュ氏 これまでのところ最良の答えがありましたが、以下の解決策は以下の利点を追加することによって(私にとって)それを理想的にします:
ルーター内:
.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
])
tosh shimayama に感謝します。
サービスを$scope
に直接入れるのはそれほどきれいではないと思ったので、ここに私のわずかなバリエーションを示します。 http://plnkr.co/edit/QJbuZZnZEDOBcYrJXWWs =
コントローラー(元の答えでは少しおかしく見えた)がActionBarオブジェクトを作成し、これが$ scopeに詰め込まれています。
オブジェクトは、実際にサービスを照会する責任があります。また、$ scopeからテンプレートURLを設定する呼び出しを非表示にします、代わりに他のコントローラーがURLを設定するために使用できます。