web-dev-qa-db-ja.com

AngularJSサービスでのデータバインディングの処理

データがサービスに保存されているときに、バインディングを適切に処理する方法を理解しようとしています。

サービスを$ scopeに入れてから、テンプレートを直接バインドすれば、問題なく動作するようになりますが、それは本当に悪い考えのようです。

基本的には、ビュー/コントローラーがサービスの状態を簡単に変更して、それをどこにでも反映できるようにしたいと思います。

次のようなことができるはずなのに、うまくいかない(http://jsfiddle.net/aidankane/AtRVD/1/)。

HTML

<div ng-controller="MyCtl">
    <select ng-model="drawing" ng-options="d.file for d in drawings"></select>
</div>
<div ng-controller="MyOtherCtl">
    {{ drawing }}
</div>

JS

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

myApp.factory('myService', function(){
    var me = {
        drawings: [{'file':'a'}, {'file':'b'}]
    };
    // selected drawing
    me.drawing = me.drawings[0];
    return me;
});

function MyCtl($scope, myService){
    // can do:
    // $scope.mys = myService;
    // and then in html ng-model="mys.drawing"
    // but that seems wrong

    $scope.drawings = myService.drawings;
    $scope.drawing = myService.drawing;

    // can I not do this? it doesn't seem to work anyway...
    $scope.$watch('drawing', function(drawing){
        myService.drawing = drawing;
    });
}

function MyOtherCtl($scope, myService){
    $scope.drawing = myService.drawing;
}

MyCtl.$inject = ['$scope', 'myService'];
MyOtherCtl.$inject = ['$scope', 'myService'];
20
Aidan Kane

$watchを使用してサービスにバインドし、関数を渡すことができます。

$scope.$watch( function () { return myService.drawing; }, function ( drawing ) {
  // handle it here. e.g.:
  $scope.drawing = drawing;
});

次に、テンプレートで$scope.drawingを使用すると、テンプレートが自動的に更新されます。

<div ng-controller="MyOtherCtl">
  {{ drawing }}
</div>
41

サービスからのデータをバインドするには、2つの方法があります。1)値による(サービスプリミティブ値への変数の変更をチェックするために上記のようにウォッチャーが必要になります)2)参照による(値は直接リンクされています)これはデータバインディングの私の好ましい方法です。

受け入れられた回答はすでにウォッチャーを実装する方法を示しているため、2番目の可能性についてのみ説明します。 このブログは私が非常によく説明しようとしていることを説明しています

参照によるデータバインディングを説明するためにこのプランクを作成しました。

これがプランクからのコードです:

HTML

<!DOCTYPE html>
<html ng-app="myApp">

  <head>
    <script data-require="[email protected]" data-semver="1.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body ng-controller="myAppCntrl">
    <h1>Hello Plunker!</h1>
    <h3>By value</h3>
    <p>{{byValue}}</p>
    <p>{{objByValue}}</p>
    <h3>By object in service reference</h3>
    <p>{{byRefence.stringPrimitive}}</p>
    <h3>By reference to service singleton</h3>
    <p>{{myservice.stringPrimitive}}</p>
    <p style="color: green">of course, you can reference an object through the service as well</p>
    <p>{{myservice.objectWithPrimitive.stringPrimitive}}</p>

    <button ng-click=update()>Update strings on service</button>
    <br />
    <button ng-click=setDefaults()>Restore Defaults</button>
  </body>

</html>

JAVASCRIPT

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

myApp.controller('myAppCntrl', function($scope, myAppService){
  $scope.myservice = myAppService;
  $scope.byValue = myAppService.stringPrimitive;
  $scope.objByValue = myAppService.objectWithPrimitive.stringPrimitive;
  $scope.byRefence = myAppService.objectWithPrimitive;

  $scope.update = function () {
    myAppService.stringPrimitive = "updated string";
    myAppService.objectWithPrimitive.stringPrimitive = "updated string here too";
  };
  $scope.setDefaults = function () {
    myAppService.stringPrimitive = 'string primitive';
    myAppService.objectWithPrimitive.stringPrimitive = 'string primitive';
  };
});

myApp.service('myAppService', function(){
  this.stringPrimitive = 'string primitive';
  this.objectWithPrimitive = {
    stringPrimitive: 'string primitive'
  };
});

では、これはどのように機能しますか?

これはangularの動作とはほとんど関係がなく、Javascriptの動作とは大きく関係していることを理解することが重要です。変数がプリミティブ値と等しく設定されている場合(またはに渡されている場合)関数)javascript(整数、文字列など)変数は値によって設定されます。これは、新しい変数が変数のコピーであることを意味します。変数がjavascriptのオブジェクトと等しく設定されている(または関数に渡されている)場合、変数は参照によって設定されます

これはどういう意味ですか?

$ scope変数が値で設定され、サービス変数が変更されると、$ scope変数はサービス変数のコピーにすぎないため、サービス変数はサービス変数とは関係がなくなり、サービス時に変更されません。 varは行います。

$ scope varがandobjectと等しく設定されている場合、参照によって割り当てられます。これは、サービスオブジェクト(サービスはnewキーワードでインスタンス化され、サービス内で「this」を使用してそのオブジェクトを参照できるため、サービスはオブジェクトであることに注意してください)または参照されるサービス上のオブジェクトが変更された場合、これらのオブジェクトを参照する$ scope変数も更新されます。

2
Nick Brady

さらにエレガントなのは、promiseを操作して($q.deferred()を参照)、それらを非同期で解決することだと思います。次に、promise関数で、データを$scopeのメンバーに割り当てることができます。

2
Barth Zalewski