web-dev-qa-db-ja.com

AngularJS:コントローラ間で変数をやりとりする方法は?

2つのAngularコントローラがあります。

function Ctrl1($scope) {
    $scope.prop1 = "First";
}

function Ctrl2($scope) {
    $scope.prop2 = "Second";
    $scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}

Ctrl1の内部でCtrl2を使用することはできません。未定義のためです。しかし、私がそのようにそれを渡してみると…

function Ctrl2($scope, Ctrl1) {
    $scope.prop2 = "Second";
    $scope.both = Ctrl1.prop1 + $scope.prop2; //This is what I would like to do ideally
}

エラーが出ます。誰もがこれを行う方法を知っていますか?

やる

Ctrl2.prototype = new Ctrl1();

また失敗します。

注: これらのコントローラは、互いに入れ子になっていません。

323
dopatraman

複数のコントローラ間で変数を共有する1つの方法は、 サービスを作成する を使用し、それを使用したい任意のコントローラに注入することです。

簡単なサービスの例:

angular.module('myApp', [])
    .service('sharedProperties', function () {
        var property = 'First';

        return {
            getProperty: function () {
                return property;
            },
            setProperty: function(value) {
                property = value;
            }
        };
    });

コントローラでサービスを使用する:

function Ctrl2($scope, sharedProperties) {
    $scope.prop2 = "Second";
    $scope.both = sharedProperties.getProperty() + $scope.prop2;
}

これは このブログ (特にレッスン2以降)で詳しく説明されています。

複数のコントローラにまたがってこれらのプロパティにバインドする場合は、バインドされた参照を保持するためにプリミティブ型(boolean、string、number)ではなくオブジェクトのプロパティにバインドするほうが効果的です。

例:var property = { Property1: 'First' };の代わりにvar property = 'First';


UPDATE: (うまくいけば)物事をより明確にするために これはフィドルです これは以下の例を示します:

  • 共有値の静的コピーへのバインド(myController1内)
    • プリミティブにバインドする(String)
    • オブジェクトのプロパティへのバインド(スコープ変数に保存)
  • 値が更新されたときにUIを更新する共有値へのバインディング(myController2内)
    • プリミティブを返す関数にバインドする(string)
    • オブジェクトのプロパティへのバインド
    • オブジェクトのプロパティへの双方向バインディング
498
Gloopy

簡単な例で簡単なことを説明するのが好きです。

これは非常に単純なServiceの例です。


angular.module('toDo',[])

.service('dataService', function() {

  // private variable
  var _dataObj = {};

  // public API
  this.dataObj = _dataObj;
})

.controller('One', function($scope, dataService) {
  $scope.data = dataService.dataObj;
})

.controller('Two', function($scope, dataService) {
  $scope.data = dataService.dataObj;
});

そして ここでjsbin

そして、これは非常に単純なFactoryの例です。


angular.module('toDo',[])

.factory('dataService', function() {

  // private variable
  var _dataObj = {};

  // public API
  return {
    dataObj: _dataObj
  };
})

.controller('One', function($scope, dataService) {
  $scope.data = dataService.dataObj;
})

.controller('Two', function($scope, dataService) {
  $scope.data = dataService.dataObj;
});

そして ここでjsbin


それがあまりにも単純であるならば、 これはより洗練された例です

関連するベストプラクティスのコメントについては、こちらの回答を参照してください

44
Dmitri Zaitsev

---私はこの質問に対する回答ではないことを知っていますが、この質問を読み、問題を回避するために工場などのサービスを処理したいという人々が欲しいのですが----

これには、サービスまたはファクトリーを使用する必要があります。

サービスは BEST PRACTICE で、入れ子になっていないコントローラ間でデータを共有します。

データ共有に関するこのトピックに関する非常に優れた注釈は、オブジェクトを宣言する方法です。それを読む前にAngularJSトラップに陥ったので不運でした、そして私は非常にイライラしました。それで私はあなたがこの悩みを避けるのを手伝いましょう。

私は "ng-book:AngularJSに関する完全な本"から読んだのですが、裸データとしてコントローラに作成されたAngularJSのng-modelsは間違っています。

$ scope要素は次のように作成する必要があります。

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // best practice, always use a model
  $scope.someModel = {
    someValue: 'hello computer'
  });

そして、これは好きではありません。

angular.module('myApp', [])
.controller('SomeCtrl', function($scope) {
  // anti-pattern, bare value
  $scope.someBareValue = 'hello computer';
  };
});

これは、DOM(html文書)が次のように呼び出しを含むことが推奨されているためです(ベストプラクティス)。

<div ng-model="someModel.someValue"></div>  //NOTICE THE DOT.

あなたの子コントローラが親コントローラからオブジェクトを変更できるようにしたい場合、これは入れ子になったコントローラにとって非常に役に立ちます。

しかし、あなたの場合はスコープを入れ子にしたくありませんが、サービスからコントローラにオブジェクトを取得するための同様の側面があります。

あなたのサービスが 'Factory'で、戻りスペースにobjectCを含むobjectBを含むobjectAがあるとしましょう。

あなたのコントローラからobjectCを自分のスコープにGETしたいのであれば、これは間違いです。

$scope.neededObjectInController = Factory.objectA.objectB.objectC;

それはうまくいかない... 代わりに1つのドットだけを使う。

$scope.neededObjectInController = Factory.ObjectA;

それから、DOMではobjectAからobjectCを呼び出すことができます。これは工場に関連するベストプラクティスであり、最も重要なことは、 予期しないエラーやキャッチ不可能なエラーを回避するのに役立ちます。

26
AFP_555

Serviceを作成せずに$ rootScopeを使用して解決する:

アプリコントローラ間でプロパティを共有するには、Angular $ rootScopeを使用できます。これはデータを共有するもう1つの方法で、人々がそれを知ることができるようにします。

いくつかの機能をコントローラ間で共有するための推奨される方法は、サービスです。$ rootscopeを使用してグローバルプロパティを読み取りまたは変更することができます。

var app = angular.module('mymodule',[]);
app.controller('Ctrl1', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = true;
}]);

app.controller('Ctrl2', ['$scope','$rootScope',
  function($scope, $rootScope) {
    $rootScope.showBanner = false;
}]);

テンプレートで$ rootScopeを使用する($ rootでプロパティにアクセスする):

<div ng-controller="Ctrl1">
    <div class="banner" ng-show="$root.showBanner"> </div>
</div>
17
Sanjeev

上記のサンプルは魅力的なように機能しました。複数の値を管理する必要がある場合に備えて、変更を加えました。これが役に立つことを願っています!

app.service('sharedProperties', function () {

    var hashtable = {};

    return {
        setValue: function (key, value) {
            hashtable[key] = value;
        },
        getValue: function (key) {
            return hashtable[key];
        }
    }
});
8
Juan Zamora

私は値を使う傾向があります、なぜこれが悪い考えであるかについて議論する誰かにとって幸せです..

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

myApp.value('sharedProperties', {}); //set to empty object - 

それからサービスに従って値を注入します。

Ctrl1に設定します。

myApp.controller('ctrl1', function DemoController(sharedProperties) {
  sharedProperties.carModel = "Galaxy";
  sharedProperties.carMake = "Ford";
});

そしてctrl2からのアクセス:

myApp.controller('ctrl2', function DemoController(sharedProperties) {
  this.car = sharedProperties.carModel + sharedProperties.carMake; 

});
6
Chilledflame

私はこの質問に貢献したいのですが、コントローラ間で、さらにはディレクティブ間でもデータを共有するための推奨方法は、すでに指摘したようにサービス(ファクトリ)を使用することです。それを行う方法の実用的な例を実行する必要があります。

これは実用的なプランカーです: http://plnkr.co/edit/Q1VdKJP2tpvqqJL1LF6m?p=info

まず、 create your service で、 共有データ になります。

app.factory('SharedService', function() {
  return {
    sharedObject: {
      value: '',
      value2: ''
    }
  };
});

それから、単にあなたの controllers にそれを注入し、あなたのスコープ上の共有データをつかみます:

app.controller('FirstCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

app.controller('SecondCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

app.controller('MainCtrl', function($scope, SharedService) {
  $scope.model = SharedService.sharedObject;
});

ディレクティブ に対しても同じことができます。

app.directive('myDirective',['SharedService', function(SharedService){
  return{
    restrict: 'E',
    link: function(scope){
      scope.model = SharedService.sharedObject;
    },
    template: '<div><input type="text" ng-model="model.value"/></div>'
  }
}]);

この実用的でクリーンな答えが誰かに役立つことを願っています。

4
Fedaykin

次の例は、 兄弟 controllersの間で変数を渡す方法を示しており、値が変化したときにアクションを実行します。

使用例:サイドバーに別のビューの内容を変更するフィルタがあります。

angular.module('myApp', [])

  .factory('MyService', function() {

    // private
    var value = 0;

    // public
    return {
      
      getValue: function() {
        return value;
      },
      
      setValue: function(val) {
        value = val;
      }
      
    };
  })
  
  .controller('Ctrl1', function($scope, $rootScope, MyService) {

    $scope.update = function() {
      MyService.setValue($scope.value);
      $rootScope.$broadcast('increment-value-event');
    };
  })
  
  .controller('Ctrl2', function($scope, MyService) {

    $scope.value = MyService.getValue();

    $scope.$on('increment-value-event', function() {    
      $scope.value = MyService.getValue();
    });
  });
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="myApp">
  
  <h3>Controller 1 Scope</h3>
  <div ng-controller="Ctrl1">
    <input type="text" ng-model="value"/>
    <button ng-click="update()">Update</button>
  </div>
  
  <hr>
  
  <h3>Controller 2 Scope</h3>
  <div ng-controller="Ctrl2">
    Value: {{ value }}
  </div>  

</div>
4
Zanon

あなたはサービスや工場でそれをすることができます。それらは、いくつかの中心的な違いを除けば本質的に同じです。この説明が thinkster.io にあるのが一番わかりやすいと思いました。シンプルで、要点を言えば効果的です。

3
Noahdecoco

プロパティをスコープの親にすることもできませんか。

$scope.$parent.property = somevalue;

私はそれが正しいと言っているのではありませんが、それはうまくいきます。

2
SideFX

ああ、もう一つの選択肢として、この新しいものを少し持ってください。それはローカルストレージであり、角度が機能する場所で機能します。どういたしまして。 (しかし、本当に、男に感謝します)

https://github.com/gsklee/ngStorage

デフォルトを定義します。

$scope.$storage = $localStorage.$default({
    prop1: 'First',
    prop2: 'Second'
});

値にアクセスします。

$scope.prop1 = $localStorage.prop1;
$scope.prop2 = $localStorage.prop2;

値を保存する

$localStorage.prop1 = $scope.prop1;
$localStorage.prop2 = $scope.prop2;

アプリにはngStorageを、コントローラーには$ localStorageをインジェクションすることを忘れないでください。

2
kJamesy

第二のアプローチ:

angular.module('myApp', [])
  .controller('Ctrl1', ['$scope',
    function($scope) {

    $scope.prop1 = "First";

    $scope.clickFunction = function() {
      $scope.$broadcast('update_Ctrl2_controller', $scope.prop1);
    };
   }
])
.controller('Ctrl2', ['$scope',
    function($scope) {
      $scope.prop2 = "Second";

        $scope.$on("update_Ctrl2_controller", function(event, prop) {
        $scope.prop = prop;

        $scope.both = prop + $scope.prop2; 
    });
  }
])

HTML:

<div ng-controller="Ctrl2">
  <p>{{both}}</p>
</div>

<button ng-click="clickFunction()">Click</button>

詳細はplunkerを見てください。

http://plnkr.co/edit/cKVsPcfs1A1Wwlud2jtO?p=preview

1
Codiee

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

1)get/setサービスを利用する

2)$scope.$emit('key', {data: value}); //to set the value

 $rootScope.$on('key', function (event, data) {}); // to get the value
1
Rohan Kawade

あなたがサービスを作りたくないなら、あなたはこのようにすることができます。

var scope = angular.element("#another ctrl scope element id.").scope();
scope.plean_assign = some_value;
0
thanksnote