回答:
私はこれを行うための最良の方法を見つけるのに少し時間をかけました。また、ユーザーがページを離れて[戻る]ボタンを押したときに、元のページに戻るために、状態を維持したいと思っていました。すべてのデータをルートスコープに入れるだけではありません。
最終結果は、各コントローラーにサービスを提供することです。コントローラーには、気にしない関数と変数があり、それらがクリアされている場合のみです。
コントローラーのサービスは、依存関係の注入によって注入されます。サービスはシングルトンであるため、それらのデータはコントローラー内のデータのように破棄されません。
サービスでは、モデルがあります。モデルにはデータのみがあり、関数はありません。そうすれば、JSONとの間で相互に変換して永続化できます。永続化のためにhtml5 localstorageを使用しました。
最後に私が使用window.onbeforeunload
して$rootScope.$broadcast('saveState');
、すべてのサービスは、彼らが自分の状態を保存しなければならない、とすることを知っているように$rootScope.$broadcast('restoreState')
、彼らが(それぞれのページに戻るには、ときに、ユーザーの葉ページやプレス戻るボタンを使用)その状態を復元するために知っているように。
私のuserControllerのuserServiceというサービスの例:
app.factory('userService', ['$rootScope', function ($rootScope) {
var service = {
model: {
name: '',
email: ''
},
SaveState: function () {
sessionStorage.userService = angular.toJson(service.model);
},
RestoreState: function () {
service.model = angular.fromJson(sessionStorage.userService);
}
}
$rootScope.$on("savestate", service.SaveState);
$rootScope.$on("restorestate", service.RestoreState);
return service;
}]);
userControllerの例
function userCtrl($scope, userService) {
$scope.user = userService;
}
ビューはこのようにバインディングを使用します
<h1>{{user.model.name}}</h1>
そして、中にアプリモジュール、実行機能の中に私が扱う放送のステートセーブとrestoreStateを
$rootScope.$on("$routeChangeStart", function (event, next, current) {
if (sessionStorage.restorestate == "true") {
$rootScope.$broadcast('restorestate'); //let everything know we need to restore state
sessionStorage.restorestate = false;
}
});
//let everthing know that we need to save state now.
window.onbeforeunload = function (event) {
$rootScope.$broadcast('savestate');
};
私が述べたように、これはこの時点に来るのにしばらくかかりました。これは非常にクリーンな方法ですが、Angularで開発するときに非常に一般的な問題であると私が疑うようなことをするのは、かなりのエンジニアリングです。
見やすくしたいのですが、ユーザーがページを離れてページに戻ったときなど、コントローラー全体の状態を維持するためのクリーンな方法として。
$scope.user = userService;
:あなたはこのような何かを持っています$scope.name = userService.model.name; $scope.email = userService.model.email;
。機能するか、ビュー内の変数を変更しても、サービス内では変更されませんか?
答えには少し遅れますが、いくつかのベストプラクティスでフィドルを更新しました
var myApp = angular.module('myApp',[]);
myApp.factory('UserService', function() {
var userService = {};
userService.name = "HI Atul";
userService.ChangeName = function (value) {
userService.name = value;
};
return userService;
});
function MyCtrl($scope, UserService) {
$scope.name = UserService.name;
$scope.updatedname="";
$scope.changeName=function(data){
$scope.updateServiceName(data);
}
$scope.updateServiceName = function(name){
UserService.ChangeName(name);
$scope.name = UserService.name;
}
}
updateService
コントローラーが破壊されたときに呼び出される必要があります $scope.$on('$destroy', function() { console.log('Ctrl destroyed'); $scope.updateServiceName($scope.name); });
$ rootScopeは大きなグローバル変数であり、1回限りのものや小さなアプリに適しています。モデルや動作をカプセル化したい場合は、サービスを使用してください(他の場所で再利用することもできます)。言及されているOPのgoogleグループ投稿に加えて、https://groups.google.com/d/topic/angular/eegk_lB6kVs/discussionも参照してください。
Angularは、あなたが探しているものをそのまま提供するわけではありません。あなたが何をしているかを達成するために私がすることは、次のアドオンを使用することです
これら2つは、状態ベースのルーティングとスティッキー状態を提供します。状態間でタブを付けることができ、すべての情報は、いわば「生存し続ける」スコープとして保存されます。
どちらも非常にわかりやすいので、両方のドキュメントを確認してください。UIルーターエクストラには、スティッキーステートがどのように機能するかを示す優れたデモもあります。
私は同じ問題を抱えていました、これは私がやったことです:同じページに複数のビューを持つSPAが(ajaxなしで)あるので、これはモジュールのコードです:
var app = angular.module('otisApp', ['chieffancypants.loadingBar', 'ngRoute']);
app.config(['$routeProvider', function($routeProvider){
$routeProvider.when('/:page', {
templateUrl: function(page){return page.page + '.html';},
controller:'otisCtrl'
})
.otherwise({redirectTo:'/otis'});
}]);
私はすべてのビューに1つのコントローラーしかありませんが、問題は質問と同じです。コントローラーは常にデータを更新します。この動作を回避するために、私は上記の人々が提案したことを行い、その目的のためにサービスを作成してから渡しました次のようにコントローラに:
app.factory('otisService', function($http){
var service = {
answers:[],
...
}
return service;
});
app.controller('otisCtrl', ['$scope', '$window', 'otisService', '$routeParams',
function($scope, $window, otisService, $routeParams){
$scope.message = "Hello from page: " + $routeParams.page;
$scope.update = function(answer){
otisService.answers.push(answers);
};
...
}]);
これで、ビューのいずれかからupdate関数を呼び出し、値を渡してモデルを更新できます。永続データにhtml5 APIを使用する必要はありません(これは私の場合ですが、他の場合にはhtml5を使用する必要があります) localstorageやその他のもののようなAPI)。
サービスの代替手段は、バリューストアを使用することです。
私のアプリのベースにこれを追加しました
var agentApp = angular.module('rbAgent', ['ui.router', 'rbApp.tryGoal', 'rbApp.tryGoal.service', 'ui.bootstrap']);
agentApp.value('agentMemory',
{
contextId: '',
sessionId: ''
}
);
...
次に、コントローラーで値ストアを参照します。ユーザーがブラウザを閉じても問題はないと思います。
angular.module('rbAgent')
.controller('AgentGoalListController', ['agentMemory', '$scope', '$rootScope', 'config', '$state', function(agentMemory, $scope, $rootScope, config, $state){
$scope.config = config;
$scope.contextId = agentMemory.contextId;
...
複数のスコープとそれらのスコープ内の複数の変数で機能するソリューション
このサービスは、Antonの回答に基づいていましたが、拡張性が高く、複数のスコープにわたって機能し、同じスコープ内の複数のスコープ変数を選択できます。ルートパスを使用して各スコープにインデックスを付け、次にスコープ変数名を使用して1レベル深くインデックスを付けます。
次のコードでサービスを作成します。
angular.module('restoreScope', []).factory('restoreScope', ['$rootScope', '$route', function ($rootScope, $route) {
var getOrRegisterScopeVariable = function (scope, name, defaultValue, storedScope) {
if (storedScope[name] == null) {
storedScope[name] = defaultValue;
}
scope[name] = storedScope[name];
}
var service = {
GetOrRegisterScopeVariables: function (names, defaultValues) {
var scope = $route.current.locals.$scope;
var storedBaseScope = angular.fromJson(sessionStorage.restoreScope);
if (storedBaseScope == null) {
storedBaseScope = {};
}
// stored scope is indexed by route name
var storedScope = storedBaseScope[$route.current.$$route.originalPath];
if (storedScope == null) {
storedScope = {};
}
if (typeof names === "string") {
getOrRegisterScopeVariable(scope, names, defaultValues, storedScope);
} else if (Array.isArray(names)) {
angular.forEach(names, function (name, i) {
getOrRegisterScopeVariable(scope, name, defaultValues[i], storedScope);
});
} else {
console.error("First argument to GetOrRegisterScopeVariables is not a string or array");
}
// save stored scope back off
storedBaseScope[$route.current.$$route.originalPath] = storedScope;
sessionStorage.restoreScope = angular.toJson(storedBaseScope);
},
SaveState: function () {
// get current scope
var scope = $route.current.locals.$scope;
var storedBaseScope = angular.fromJson(sessionStorage.restoreScope);
// save off scope based on registered indexes
angular.forEach(storedBaseScope[$route.current.$$route.originalPath], function (item, i) {
storedBaseScope[$route.current.$$route.originalPath][i] = scope[i];
});
sessionStorage.restoreScope = angular.toJson(storedBaseScope);
}
}
$rootScope.$on("savestate", service.SaveState);
return service;
}]);
次のコードをアプリモジュールの実行関数に追加します。
$rootScope.$on('$locationChangeStart', function (event, next, current) {
$rootScope.$broadcast('savestate');
});
window.onbeforeunload = function (event) {
$rootScope.$broadcast('savestate');
};
コントローラにrestoreScopeサービスを挿入します(以下の例):
function My1Ctrl($scope, restoreScope) {
restoreScope.GetOrRegisterScopeVariables([
// scope variable name(s)
'user',
'anotherUser'
],[
// default value(s)
{ name: 'user name', email: 'user@website.com' },
{ name: 'another user name', email: 'anotherUser@website.com' }
]);
}
上記の例は、保存された値に$ scope.userを初期化します。それ以外の場合は、デフォルトで提供された値に設定し、それを保存します。ページが閉じられたり、更新されたり、ルートが変更されたりすると、登録されているすべてのスコープ変数の現在の値が保存され、次にルート/ページにアクセスしたときに復元されます。
$locationChangeStart
イベントを使用して、以前の値を$rootScope
サービス内またはサービス内に格納できます。戻ったら、以前に保存したすべての値を初期化するだけです。これはを使用した簡単なデモ$rootScope
です。
var app = angular.module("myApp", ["ngRoute"]);
app.controller("tab1Ctrl", function($scope, $rootScope) {
if ($rootScope.savedScopes) {
for (key in $rootScope.savedScopes) {
$scope[key] = $rootScope.savedScopes[key];
}
}
$scope.$on('$locationChangeStart', function(event, next, current) {
$rootScope.savedScopes = {
name: $scope.name,
age: $scope.age
};
});
});
app.controller("tab2Ctrl", function($scope) {
$scope.language = "English";
});
app.config(function($routeProvider) {
$routeProvider
.when("/", {
template: "<h2>Tab1 content</h2>Name: <input ng-model='name'/><br/><br/>Age: <input type='number' ng-model='age' /><h4 style='color: red'>Fill the details and click on Tab2</h4>",
controller: "tab1Ctrl"
})
.when("/tab2", {
template: "<h2>Tab2 content</h2> My language: {{language}}<h4 style='color: red'>Now go back to Tab1</h4>",
controller: "tab2Ctrl"
});
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular-route.js"></script>
<body ng-app="myApp">
<a href="#/!">Tab1</a>
<a href="#!tab2">Tab2</a>
<div ng-view></div>
</body>
</html>
sessionStorage.restoreState
がに設定されて"true"
いる場所は表示されません。ページが更新されたときにデータを保持するための正しい解決策については、こちらをご覧ください。ルートが変更されたときにデータを保持するには、carloscarcamoの答えを見てください。必要なのは、データをサービスに配置することだけです。