Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
385
Help us understand the problem. What is going on with this article?
@sunny4381

Angular JS で複数のコントローラ間でモデル(状態や値)を共有する方法 3 種類

More than 5 years have passed since last update.

はじめに

Angular JS で複数のコントローラ間でモデル(状態や値)を共有する方法として、次の 3 種類を解説します。

  • モデルを共有するサービスを使用する (Shared Service)。
  • 親コントローラのスコープを子コントローラで共有する (Parent Scope Sharing)。
  • イベントを利用する (Pub/Sub)。

Shared Service

複数のコントローラ間で共有するモデルをサービスとして作成し、そのサービスを複数のコントローラで参照します。
実装例を示します。

app.html
<!DOCTYPE HTML>
<html ng-app="AngularJsStudy">
<head>
    <title>Shared State Service - AngularJS Study</title>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
</head>
<body>
    <h4>Shared State Service</h4>
    <div class="container ng-cloak" ng-controller="ShareControllerA">
        <h5>This is ShareControllerA</h5>
        <input type="text" class="form-control" ng-model="data.text">
    </div>
    <div class="container ng-cloak" ng-controller="ShareControllerB">
        <h5>This is ShareControllerB</h5>
        <input type="text" class="form-control" ng-model="data.text">
    </div>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
    <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
    <script src="app.js"></script>
</body>
</html>
app.js
(function() {
    var app = angular.module("AngularJsStudy", []);

    app.factory("SharedStateService", function() {
        return {
            text: 'SharedStateService'
        };
    });

    app.controller("ShareControllerA", function($scope, SharedStateService) {
        $scope.data = SharedStateService;
    });

    app.controller("ShareControllerB", function($scope, SharedStateService) {
        $scope.data = SharedStateService;
    });
}());

ShareControllerAShareControllerB では、スコープ $scopedataSharedStateService をバインドしています。
こうすることで、AngularJS の一番の特長であるビューとモデルの双方向バインドを効果的に利用できます。

Parent Scope Sharing

AngularJS ではコントローラをネストすることができます。
コントローラをネストした場合、子要素のコントローラは、親要素のコントローラのスコープを参照することができます。
実装例を示します。

app.html
<!DOCTYPE HTML>
<html ng-app="AngularJsStudy">
<head>
    <title>Parent Scope Sharing - AngularJS Study</title>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
</head>
<body>
    <h4>Parent Scope Sharing</h4>
    <div class="container ng-cloak" ng-controller="MasterController">
        <h5>Master Controller</h5>
        <input type="text" class="form-control" ng-model="text">
        <hr/>
        <div class="container" ng-controller="ChildControllerA">
            <h5>Child Controller A</h5>
            <input type="text" class="form-control" ng-model="$parent.text">
        </div>
        <hr/>
        <div class="container" ng-controller="ChildControllerB">
            <h5>Child Controller B</h5>
            <input type="text" class="form-control" ng-model="$parent.text">
        </div>
    </div>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
    <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
    <script src="app.js"></script>
</body>
</html>
app.js
(function() {
    var app = angular.module("AngularJsStudy", []);

    app.controller("MasterController", function($scope) {
        $scope.text = "Shared Text";
    });

    app.controller("ChildControllerA", function($scope) {
    });

    app.controller("ChildControllerB", function($scope) {
    });
}());

Shared Service と同様の方法で、こちらの方が直感的かもしれませんが、
AngularJS のお勧めではビューに無関係なロジックはサービスにとあるので、
AngularJS らしく実装したいなら Shared Service の方でしょう。

Pub/Sub

プロパティが変更されたら、$scope$emit(), $broadcast() メソッドを利用してイベントを送信し、
$scope$on メソッドでイベントを受信する方法です。
実装例を示します。

app.html
<!DOCTYPE HTML>
<html ng-app="AngularJsStudy">
<head>
    <title>Pub/Sub - Share State</title>
    <meta charset="utf-8" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
</head>
<body>
    <h4>Pub/Sub</h4>
    <div class="container" ng-controller="Controller">
        <h5>Controller 1</h5>
        <input type="text" class="form-control" ng-model="text">
        <button type="button" class="btn btn-default" ng-click="setText()">設定</button>
    </div>
    <hr/>
    <div class="container" ng-controller="Controller">
        <h5>Controller 2</h5>
        <input type="text" class="form-control" ng-model="text">
        <button type="button" class="btn btn-default" ng-click="setText()">設定</button>
    </div>

    <script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
    <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
    <script src="app.js"></script>
</body>
</html>
app.js
(function() {
    var app = angular.module("AngularJsStudy", []);

    app.factory("SharedService", ["$rootScope", function($rootScope) {
        var text = "Shared Text";

        return {
            text: {
                get: function() { return text; },
                set: function(t) {
                    console.log("[enter] text.set");
                    text = t;
                    $rootScope.$broadcast('changedText');
                    console.log("[leave] text.set");
                }
            }
        };
    }]);

    app.controller("Controller", function($scope, SharedService) {
        $scope.text = SharedService.text.get();

        $scope.setText = function() {
            console.log("[enter] setText");
            SharedService.text.set($scope.text);
            console.log("[leave] setText");
        };

        $scope.$on('changedText', function() {
            console.log("[enter] changedText");
            $scope.text = SharedService.text.get();
            console.log("[leave] changedText");
        });
    });
}());

実装例ではすべてのコントローラにイベントが届くように $rootScope$broadcast() メソッドを利用してイベントを送信しています。

参考

参考サイトによると directive を用いてモデルを共有する方法もあるようです。

385
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
385
Help us understand the problem. What is going on with this article?