23

カスタム ディレクティブに問題があり、頭がおかしくなりました。次のカスタム (属性) ディレクティブを作成しようとしています。

angular.module('componentes', [])
    .directive("seatMap", function (){
        return {
            restrict: 'A',
            link: function(scope, element, attrs, controller){

                function updateSeatInfo(scope, element){
                    var txt = "";
                    for (var i in scope.seats)
                        txt = txt + scope.seats[i].id + " ";
                    $(element).text("seat ids: "+txt);
                }

                /* 
                    // This is working, but it's kind of dirty...
                    $timeout(function(){updateSeatInfo(scope,element);}, 1000);
                */

                scope.$watch('seats', function(newval, oldval){
                    console.log(newval, oldval);
                    updateSeatInfo(scope,element);
                });
            }
        }
    });

この「attribute-type」ディレクティブ (seatMap と呼ばれる) は、$resource サービス (以下のコードを参照) を介してサーバーから div (要素) にフェッチする座席 ID (劇場など) のリストを表示しようとしています。 .

私はこの単純な部分的なhtmlでそれを使用しています:

<div>
    <!-- This is actually working -->
    <ul>
        <li ng-repeat="seat in seats">{{seat.id}}</li>
    </ul>

    <!-- This is not... -->
    <div style="border: 1px dotted black" seat-map></div>
</div>

そして、これはスコープをロードしているコントローラーです:

function SeatsCtrl($scope, Seats) {
    $scope.sessionId = "12345";
    $scope.zoneId = "A";
    $scope.seats = Seats.query({sessionId: $scope.sessionId, zoneId: $scope.zoneId});
    $scope.max_seats = 4;
}

"Seats" は、$resources を使用してサーバーから JSON をフェッチする単純なサービスです。

angular.module('myApp.services', ['ngResource'])
    .factory('Seats', function($resource){
        return $resource('json/seats-:sessionId-:zoneId.json', {}, {});
    })
;

app.js (asientos_libres.html は私が使っている部分です):

angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'componentes']).
  config(['$routeProvider', function($routeProvider) {
    $routeProvider.when('/view1', {templateUrl: 'partials/asientos_libres.html', controller: SeatsCtrl});
    $routeProvider.otherwise({redirectTo: '/view1'});
  }]);

問題は、ディレクティブのリンク関数に「scope.$watch」を設定して、スコープが「seats」属性が変更されて ID のリストを更新するかどうかを確認できるようにしたにもかかわらず、それが動作していないことです。コントローラーで $scope.seats が変更されている瞬間 (「クエリ」を呼び出したとき)。

コードでわかるように、$timeout を使用して「updateSeatInfo」の起動を遅らせようとしましたが、これは最も賢明な解決策ではないと思います...

また、JSON リクエストを作成しないようにしましたが、$scope.seats でハードコードされた辞書を使用して動作するため、同期の問題のようです。

注: updateSeatInfo は単なるテスト関数です。実際に使用する関数はもう少し複雑です。

それに対処する方法について何か考えはありますか?

よろしくお願いします!

編集 1:ルーターを使用して SeatsCtrl を呼び出す app.js を追加しました。Supr のアドバイスに感謝します。しかし、私はまだ同じ問題を抱えています。

編集 2: 解決!(?) OK! 最善ではないかもしれない解決策を見つけたようですが、正しく機能しています! :) ここhttp://docs.angularjs.org/api/ng.$timeoutを見ることができる限り、遅延なしで$timeout (setTimeout のラッパー) を使用できます! $timeout 内で人為的にコードの実行を遅らせていないため、これは素晴らしいことですが、非同期リクエストが終了するまでコードを実行しないようにディレクティブを作成しています。

待ち時間の長いリクエストにも対応できることを願っています...

誰かがそれを修正するより良い方法を知っているなら、教えてください!

4

4 に答える 4

56

問題は、ウォッチがデフォルトでオブジェクトではなく参照を比較することです。最後に ,true を追加して、代わりに値を比較します。

scope.$watch('seats', function(newval, oldval){
                console.log(newval, oldval);
                updateSeatInfo(scope,element);
            }, true);
于 2012-10-19T00:25:16.607 に答える
5

私もこの問題を抱えていました。これは、私の変数が最初はスコープ内で「未定義」に定義されていなかったことが原因でした。Watch は未定義の変数では機能しないようです。結局のところ、明らかなようです。

私は最初に、変数がコントローラーによって効果的に設定されるときに、watch を使用してトリガーしようとしていました。例:

myApp.controller('Tree', function($scope, Tree) {

Tree.get({},
function(data) { // SUCCESS
    console.log("call api Tree.get succeed");
    $scope.treeData = data;
},

function(data) { // FAILURE
    console.log("call api Tree.get failed");
    $scope.treeData = {};
});
});

サービスを呼び出す前に、変数を空のオブジェクトで初期化することで解決しました。

myApp.controller('Tree', function($scope, Tree) {

$scope.treeData = {};      // HERE

Tree.get({},
function(data) { // SUCCESS
    console.log("call api Tree.get succeed");
    $scope.treeData = data;
},

function(data) { // FAILURE
    console.log("call api Tree.get failed");
    $scope.treeData = {};
});
});

その場合、watch は変数の変化を検出できました。

于 2012-12-29T13:47:45.343 に答える
0

SeatsCtrl-controller をどこでも使用しているように見えませんか? どのように使用されていますか?また、それがアクティブ化されていること、およびクエリが実際に実行されることを確認しましたか?

SeatsCtrl が使用されているかどうかを確認する最も簡単な方法は、そのconsole.log('SeatsCtrl actived!');中に a を追加することです。そうでない場合は、 に追加ng-controller="SeatsCtrl"divます。

また、スコーピングに問題がないことを確認するために、コントローラー内のシートに監視とログを直接配置することもできます.

于 2012-06-21T11:19:14.320 に答える
0

私もこの問題を抱えています。Angularの問題だと思います。本当に必要なのは、あなたが持っているリソースの promise オブジェクトへのアクセスであるため、おそらくこの問題に対処する"beef up $resource futures"へのチケットが GitHub にあります。

または、promise が解決されるまでウォッチャーが発砲するのを待つこともできます。

それまでの間、タイムアウトを必要としない、これを修正するもう少し洗練された方法は、$resource の成功コールバックから監視されているスコープ プロパティを再割り当てすることです。これにより、適切なタイミングでウォッチャーが再び起動します。

遅延のないタイムアウトは、遅延関数の評価を現在のスタックの最後に置くだけです-あなたの場合、リソースはたまたまそれまでに解決されましたが、サーバーに問題がある場合、これは問題になる可能性があります月曜日。

例:

$scope.myAttr = MyResource.fetch(
  function (resource) { $scope.myAttr = new MyResource(angular.copy(resource)); }
);
于 2012-08-31T17:56:07.503 に答える