Works by

Ren's blog

@rennnosuke_rk 技術ブログです

【AngularJS】Serviceを用いた画面遷移時のパラメータ受け渡し

画面遷移時にパラメータを受け渡す

AngularJSでは画面遷移が発生する(厳密には画面遷移というよりng-viewによる一部HTMLの差し替え)と、多くの場合Controllerも遷移先のViewに合わせて切り替わります。

このとき、遷移前に利用していたController上のパラメータを遷移後のControllerでも利用したいことがよくあります。

パラメータの渡し方はいくつか方法があるのですが、今回はServiceを利用したパラメータ渡しを紹介します。

なぜServiceなのか

$rootScopeを使うことでも、画面遷移時のパラメータ受け渡しは可能です。

let module = angular.module('myApp');
module.controller('ControllerA', [$rootScope, function($rootScope){
    // Controller A
    $rootScope.value = "value";
    $location.path("/b");
}]);
module.controller('ControllerB', [$rootScope, function($rootScope){
    // Controller B
    $scope.value = $rootScope.value;
}]);

ただし$rootScopeは他の用途でも用いられる上、名前空間の管理をきちんと行わないと
名前が競合してパラメータが上書きされるなどの問題が発生します。

let module = angular.module('myApp');
module.controller('ControllerA', [$rootScope, function($rootScope){
    // Controller A
    $rootScope.value = "value";
    $location.path("/b");
}]);
module.controller('ControllerB', [$rootScope, function($rootScope){
    // Controller B
    // Controller Aから遷移
    $scope.value = $rootScope.value;
}]);
module.controller('ControllerC', [$rootScope, function($rootScope){
    // Controller C
    // 別の用途で$rootScopeを利用
    $scope.value = 3;
}]);

一方、画面遷移パラメータ保持専用のServiceを作ることで、そのインスタンスは「パラメータ受け渡し専用」ということを明示でき、パラメータが上書きされる危険性をぐっと抑えることができます。

実装、Usage

ディレクトリ構成は以下の通り。

.
├── index.html
├── js
│   └── app.js
└── view
    ├── a.html
    └── b.html
index.html
<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <meta charset="utf-8"/>
    <title>AngularJS - Passing Parameter to another window with Service. </title>
</head>
<body>
    <div ng-View></div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.5/angular-route.min.js"></script>
    <script src="js/app.js"></script>
</body>
</html>
app.js
let mod = angular.module('myApp', ['ngRoute']);

// パラメータコンテナとして働くService
// 実際は単一のパラメータコンテナだけを用意するのではなく、各Controller用にコンテナ用意するなどして競合を防ぐ
mod.service('paramService', function(){
  this.firstMessage = null;
  this.secondMessage = null;
  this.thirdMessage = null;
});

// 遷移前画面に対応するController
mod.controller('ACtrl', ['$scope', '$location', 'paramService', function($scope, $location, paramService){

  $scope.firstMessage = "first message .";
  $scope.secondMessage = "second message .";
  $scope.thirdMessage = "third message .";

  // ボタンを押したらパラメータをServiceにセット+画面遷移
  $scope.onButtonClick = function() {
    paramService.firstMessage = $scope.firstMessage;
    paramService.secondMessage = $scope.secondMessage;
    paramService.thirdMessage = $scope.thirdMessage;
    console.log("test");
    $location.path("/b");
  };

}]);

// 遷移後画面に対応するController
mod.controller('BCtrl', ['$scope', 'paramService', function($scope, paramService){
    // 受け取ったパラメータをテンプレートにセット
    $scope.firstMessage = paramService.firstMessage;
    $scope.secondMessage = paramService.secondMessage;
    $scope.thirdMessage = paramService.thirdMessage;
}]);

// ルーティング設定
mod.config(['$routeProvider', function($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: 'view/a.html',
      controller: 'ACtrl'
    })
    .when('/b', {
      templateUrl: 'view/b.html',
      controller: 'BCtrl'
    })
    .otherwise({
      redirectTo: '/'
    });
}]);
a.html
<!-- A -->
<div>
    <p>{{firstMessage}}</p>
    <p>{{secondMessage}}</p>
    <p>{{thirdMessage}}</p>
    <input type=button value="nextPage" ng-click="onButtonClick()"/>
</div>
b.html
<!-- B -->
<div>
  <p>{{firstMessage}}</p>
  <p>{{secondMessage}}</p>
  <p>{{thirdMessage}}</p>
</div>

参考文献

dev.classmethod.jp