web-dev-qa-db-ja.com

AngularJSコントローラ間でデータを共有する

コントローラ間でデータを共有しようとしています。ユースケースはマルチステップ形式で、1つの入力に入力されたデータは後で元のコントローラの外部の複数の表示場所で使用されます。以下のコードと ここでのjsfiddle

_ html _

<div ng-controller="FirstCtrl">
    <input type="text" ng-model="FirstName"><!-- Input entered here -->
    <br>Input is : <strong>{{FirstName}}</strong><!-- Successfully updates here -->
</div>

<hr>

<div ng-controller="SecondCtrl">
    Input should also be here: {{FirstName}}<!-- How do I automatically updated it here? -->
</div>

_ js _

// declare the app with no dependencies
var myApp = angular.module('myApp', []);

// make a factory to share data between controllers
myApp.factory('Data', function(){
    // I know this doesn't work, but what will?
    var FirstName = '';
    return FirstName;
});

// Step 1 Controller
myApp.controller('FirstCtrl', function( $scope, Data ){

});

// Step 2 Controller
myApp.controller('SecondCtrl', function( $scope, Data ){
    $scope.FirstName = Data.FirstName;
});

任意の助けは大歓迎です。

349
johnkeese

簡単な解決策は、あなたのファクトリにオブジェクトを返させ、あなたのコントローラが同じオブジェクトへの参照を使って動作するようにさせることです:

JS:

// declare the app with no dependencies
var myApp = angular.module('myApp', []);

// Create the factory that share the Fact
myApp.factory('Fact', function(){
  return { Field: '' };
});

// Two controllers sharing an object that has a string in it
myApp.controller('FirstCtrl', function( $scope, Fact ){
  $scope.Alpha = Fact;
});

myApp.controller('SecondCtrl', function( $scope, Fact ){
  $scope.Beta = Fact;
});

HTML:

<div ng-controller="FirstCtrl">
    <input type="text" ng-model="Alpha.Field">
    First {{Alpha.Field}}
</div>

<div ng-controller="SecondCtrl">
<input type="text" ng-model="Beta.Field">
    Second {{Beta.Field}}
</div>

デモ: http://jsfiddle.net/HEdJF/

アプリケーションが大きくなり、複雑になり、テストが難しくなる場合は、このようにファクトリからオブジェクト全体を公開するのではなく、例えばgetterやsetterを介してアクセスを制限したい場合があります。

myApp.factory('Data', function () {

    var data = {
        FirstName: ''
    };

    return {
        getFirstName: function () {
            return data.FirstName;
        },
        setFirstName: function (firstName) {
            data.FirstName = firstName;
        }
    };
});

このアプローチでは、新しい値でファクトリを更新し、それらを取得するための変更を監視するのは、消費するコントローラ次第です。

myApp.controller('FirstCtrl', function ($scope, Data) {

    $scope.firstName = '';

    $scope.$watch('firstName', function (newValue, oldValue) {
        if (newValue !== oldValue) Data.setFirstName(newValue);
    });
});

myApp.controller('SecondCtrl', function ($scope, Data) {

    $scope.$watch(function () { return Data.getFirstName(); }, function (newValue, oldValue) {
        if (newValue !== oldValue) $scope.firstName = newValue;
    });
});

HTML:

<div ng-controller="FirstCtrl">
  <input type="text" ng-model="firstName">
  <br>Input is : <strong>{{firstName}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
  Input should also be here: {{firstName}}
</div>

デモ: http://jsfiddle.net/27mk1n1o/ /

465
tasseKATT

これには$watchを使わない方がいいです。サービス全体をコントローラのスコープに割り当てる代わりに、データだけを割り当てることができます。

JS:

var myApp = angular.module('myApp', []);

myApp.factory('MyService', function(){
  return {
    data: {
      firstName: '',
      lastName: ''
    }
    // Other methods or objects can go here
  };
});

myApp.controller('FirstCtrl', function($scope, MyService){
  $scope.data = MyService.data;
});

myApp.controller('SecondCtrl', function($scope, MyService){
   $scope.data = MyService.data;
});

HTML:

<div ng-controller="FirstCtrl">
  <input type="text" ng-model="data.firstName">
  <br>Input is : <strong>{{data.firstName}}</strong>
</div>
<hr>
<div ng-controller="SecondCtrl">
  Input should also be here: {{data.firstName}}
</div>

あるいは、直接方法でサービスデータを更新することもできます。

JS:

// A new factory with an update method
myApp.factory('MyService', function(){
  return {
    data: {
      firstName: '',
      lastName: ''
    },
    update: function(first, last) {
      // Improve this method as needed
      this.data.firstName = first;
      this.data.lastName = last;
    }
  };
});

// Your controller can use the service's update method
myApp.controller('SecondCtrl', function($scope, MyService){
   $scope.data = MyService.data;

   $scope.updateData = function(first, last) {
     MyService.update(first, last);
   }
});
69
bennick

コントローラ間でデータを共有する方法はたくさんあります

  1. サービスを利用する
  2. $ state.goサービスを使用する
  3. stateparamsを使う
  4. ルーツスコープを使う

各方法の説明

  1. 私はそれがすでに誰かによって説明されているように説明するつもりはないです

  2. $state.goを使う

      $state.go('book.name', {Name: 'XYZ'}); 
    
      // then get parameter out of URL
      $state.params.Name;
    
  3. $stateparam$state.goと同じように機能します。送信側コントローラからオブジェクトとして渡し、stateparamを使用して受信側コントローラに収集します。

  4. $rootscopeを使う

    (a)子から親コントローラにデータを送信する

      $scope.Save(Obj,function(data) {
          $scope.$emit('savedata',data); 
          //pass the data as the second parameter
      });
    
      $scope.$on('savedata',function(event,data) {
          //receive the data as second parameter
      }); 
    

    (b)親から子へのデータ送信

      $scope.SaveDB(Obj,function(data){
          $scope.$broadcast('savedata',data);
      });
    
      $scope.SaveDB(Obj,function(data){`enter code here`
          $rootScope.$broadcast('saveCallback',data);
      });
    
10
Ayush Mishra

ルートパスのパターン間で共有範囲を制御するファクトリを作成したので、ユーザーが同じルートの親パスで移動しているときにも共有データを維持できます。

.controller('CadastroController', ['$scope', 'RouteSharedScope',
    function($scope, routeSharedScope) {
      var customerScope = routeSharedScope.scopeFor('/Customer');
      //var indexScope = routeSharedScope.scopeFor('/');
    }
 ])

そのため、ユーザーが別のルートパス、たとえば '/ Support'に移動すると、パス '/ Customer'の共有データは自動的に破棄されます。しかし、これの代わりにユーザーが「/ Customer/1」や「/ Customer/list」のように「子」パスに移動しても、スコープは破棄されません。

あなたはここでサンプルを見ることができます: http://plnkr.co/edit/OL8of9

6
Oberdan Nunes

コントローラ間でデータを共有する方法は複数あります

  • Angularサービス
  • $ broadcast、$ emitメソッド
  • 親から子へのコントローラー通信
  • $ルーツスコープ

$rootscopeは、アプリケーション全体で利用可能なグローバルスコープであるため、データ転送や通信には適していません。

AngularJsコントローラーAngularサービス間のデータ共有には、ベストプラクティスなどがあります。 .factory.service
参照 の場合

親から子コントローラへのデータ転送の場合、$scopeを通して子コントローラの親データに直接アクセスできます。
ui-routerを使用している場合は、idnamekeyなどのURLパラメータを渡すために$stateParmasを使用できます。

$broadcastは、コントローラ間でデータを親から子へ、$emitでデータを子から親へ転送するのにも良い方法です。

_ html _

<div ng-controller="FirstCtrl">
   <input type="text" ng-model="FirstName">
   <br>Input is : <strong>{{FirstName}}</strong>
</div>

<hr>

<div ng-controller="SecondCtrl">
   Input should also be here: {{FirstName}}
</div>

_ js _

myApp.controller('FirstCtrl', function( $rootScope, Data ){
    $rootScope.$broadcast('myData', {'FirstName': 'Peter'})
});

myApp.controller('SecondCtrl', function( $rootScope, Data ){
    $rootScope.$on('myData', function(event, data) {
       $scope.FirstName = data;
       console.log(data); // Check in console how data is coming
    });
});

$broadcastについてもっと知るために与えられた link を参照してください

3
ojus kulkarni

最も簡単な解決策:

AngularJSサービス を使用しました。

Step1: SharedDataServiceというAngularJSサービスを作成しました。

myApp.service('SharedDataService', function () {
     var Person = {
        name: ''

    };
    return Person;
});

Step2: 2つのコントローラを作成し、上記で作成したサービスを使用します。

//First Controller
myApp.controller("FirstCtrl", ['$scope', 'SharedDataService',
   function ($scope, SharedDataService) {
   $scope.Person = SharedDataService;
   }]);

//Second Controller
myApp.controller("SecondCtrl", ['$scope', 'SharedDataService',
   function ($scope, SharedDataService) {
   $scope.Person = SharedDataService;
   }]);

Step3: ビュー内で作成したコントローラを使うだけです。

<body ng-app="myApp">

<div ng-controller="FirstCtrl">
<input type="text" ng-model="Person.name">
<br>Input is : <strong>{{Person.name}}</strong>
</div>

<hr>

<div ng-controller="SecondCtrl">
Input should also be here: {{Person.name}}
</div>

</body>

この問題に対する有効な解決策を見るには、下のリンクを押してください

https://codepen.io/wins/pen/bmoYLr

.htmlファイル:

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.9/angular.min.js"></script>

<body ng-app="myApp">

  <div ng-controller="FirstCtrl">
    <input type="text" ng-model="Person.name">
    <br>Input is : <strong>{{Person.name}}</strong>
   </div>

<hr>

  <div ng-controller="SecondCtrl">
    Input should also be here: {{Person.name}}
  </div>

//Script starts from here

<script>

var myApp = angular.module("myApp",[]);
//create SharedDataService
myApp.service('SharedDataService', function () {
     var Person = {
        name: ''

    };
    return Person;
});

//First Controller
myApp.controller("FirstCtrl", ['$scope', 'SharedDataService',
    function ($scope, SharedDataService) {
    $scope.Person = SharedDataService;
    }]);

//Second Controller
myApp.controller("SecondCtrl", ['$scope', 'SharedDataService',
    function ($scope, SharedDataService) {
    $scope.Person = SharedDataService;
}]);

</script>


</body>
</html>
1
wins999

$ watchを使わずにangular.copyを使う方法もあります。

var myApp = angular.module('myApp', []);

myApp.factory('Data', function(){

    var service = {
        FirstName: '',
        setFirstName: function(name) {
            // this is the trick to sync the data
            // so no need for a $watch function
            // call this from anywhere when you need to update FirstName
            angular.copy(name, service.FirstName); 
        }
    };
    return service;
});


// Step 1 Controller
myApp.controller('FirstCtrl', function( $scope, Data ){

});

// Step 2 Controller
myApp.controller('SecondCtrl', function( $scope, Data ){
    $scope.FirstName = Data.FirstName;
});
1
Hinrich

これを行うには複数の方法があります。

  1. イベント - すでによく説明されています。

  2. uIルーター - 上記の説明。

  3. サービス - 上記の更新方法で
  4. _ bad _ - 変更を監視しています。
  5. emit および brodcast - ではなく別の親子アプローチ

*

<superhero flight speed strength> Superman is here! </superhero>
<superhero speed> Flash is here! </superhero>

*

app.directive('superhero', function(){
    return {
        restrict: 'E',
        scope:{}, // IMPORTANT - to make the scope isolated else we will pollute it in case of a multiple components.
        controller: function($scope){
            $scope.abilities = [];
            this.addStrength = function(){
                $scope.abilities.Push("strength");
            }
            this.addSpeed = function(){
                $scope.abilities.Push("speed");
            }
            this.addFlight = function(){
                $scope.abilities.Push("flight");
            }
        },
        link: function(scope, element, attrs){
            element.addClass('button');
            element.on('mouseenter', function(){
               console.log(scope.abilities);
            })
        }
    }
});
app.directive('strength', function(){
    return{
        require:'superhero',
        link: function(scope, element, attrs, superHeroCtrl){
            superHeroCtrl.addStrength();
        }
    }
});
app.directive('speed', function(){
    return{
        require:'superhero',
        link: function(scope, element, attrs, superHeroCtrl){
            superHeroCtrl.addSpeed();
        }
    }
});
app.directive('flight', function(){
    return{
        require:'superhero',
        link: function(scope, element, attrs, superHeroCtrl){
            superHeroCtrl.addFlight();
        }
    }
});
1
user2756335

私がどこでこのパターンを選んだのかわからないが、コントローラ間でデータを共有し、$ rootScopeと$ scopeを減らすためにこれはとてもうまくいく。それはあなたが出版社と購読者を持っているところのデータ複製を彷彿とさせます。それが役に立てば幸い。

サービス:

(function(app) {
    "use strict";
    app.factory("sharedDataEventHub", sharedDataEventHub);

    sharedDataEventHub.$inject = ["$rootScope"];

    function sharedDataEventHub($rootScope) {
        var DATA_CHANGE = "DATA_CHANGE_EVENT";
        var service = {
            changeData: changeData,
            onChangeData: onChangeData
        };
        return service;

        function changeData(obj) {
            $rootScope.$broadcast(DATA_CHANGE, obj);
        }

        function onChangeData($scope, handler) {
            $scope.$on(DATA_CHANGE, function(event, obj) {
                handler(obj);
            });
        }
    }
}(app));

パブリッシャである新しいデータを取得しているコントローラは、このようなことをするでしょう..

var someData = yourDataService.getSomeData();

sharedDataEventHub.changeData(someData);

Subscriberと呼ばれるこの新しいデータも使用しているControllerは、次のようなことをします。

sharedDataEventHub.onChangeData($scope, function(data) {
    vm.localData.Property1 = data.Property1;
    vm.localData.Property2 = data.Property2;
});

これはどんなシナリオでもうまくいきます。そのため、プライマリコントローラが初期化されてデータが取得されると、changeDataメソッドが呼び出され、それがそのデータのすべてのサブスクライバにブロードキャストされます。これにより、コントローラ間のカップリングが減少します。

0
ewahner