2012-06-21 10 views
24

私は狂ったようなカスタムディレクティブに問題があります。 私は次のカスタム(属性)ディレクティブを作成しようとしています:

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); 
       }); 
      } 
     } 
    }); 

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

私はこの単純な部分の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; 
} 

サーバーからJSONを取得するためのリソース

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

app.js(asientos_libres.htmlは、使用EEN):

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'}); 
    }]); 

問題はスコープが「席」属性を更新するために変更されているかどうかを確認することができるように、私はディレクティブのリンク機能で「スコープ$ウォッチを。」の設定にもかかわらず、ですidsのリストでは、コントローラーで$ scope.seatsが変更されているときには動作しません(「照会」と呼ばれるとき)。

あなたがコードで表示される場合がありますように、私も試した私が「updateSeatInfo」の発売を延期するために$タイムアウトを使用してみてくださいを作ったが、私はそれがはるかに賢い解決策はありません怖い...

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

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

これに対処する方法はありますか。

ありがとうございます!

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

編集2:解決済み(?) OK!それは最高のものではないかもしれない解決策を見つけたようですが、正常に機能しています! :) 私がここで見ることができる限り、http://docs.angularjs.org/api/ng.$timeoutは、遅延なしで$タイムアウト(ラッパーover setTimeout)を使用することができます!これは、$ timeout内でコードの実行を人為的に遅らせているわけではないため、非同期要求が完了するまで指令を実行しないようにしているため、これは素晴らしいことです。

誰かがそれを修正するより良い方法を知っていれば、教えてください...それはあまりにも、長い待ちのリクエストのために働くことを願っています!

答えて

57

問題は、時計は、デフォルトでは代わりにオブジェクトの参照を比較することです。追加すると、最後まで真になり、代わりに値を比較します。

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

注意点:このような深い比較では、パフォーマンスが低下します。 1つのオブジェクトではなくオブジェクトのコレクションを深く見ているときは、ほとんどの場合問題ですが、注意する価値はあります。 –

0

どこでもSeatsCtrlコントローラを使用しているのがわかりませんか?どのように使用されていますか?そして、それがアクティブになっていることと、実際にクエリが実行されていることを確認しましたか?

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

コントローラの内部に時計回りを付けるだけで、スコープに問題がないことを確認することもできます。

+0

さて、私は実際にapp.jsのルータ経由でSeatsCtrlを使用しています。以前は申し訳ありません。私はそれをもっと明確にするために投稿を編集しました。 – Sheniff

+0

私は参照してください。コントローラーが実行されていることを確認しましたか?クエリが予想通りに座席を返していますか?私が言ったように、SeatsCtrlの中に腕時計を追加すると、クエリが実行されるかどうかが明らかになります。この場合、スコープに問題がある可能性があります。 – Supr

+0

がチェックされています。クエリは**実行中ですが、タイムアウトを使用する場合に限り**です。それは指令に起こっているのと同じ問題です。 Ajax経由で($ response経由で)データを取得することは、完全に同期の問題であるようです...ところで、スコープは大丈夫です。 – Sheniff

0

この問題もあります。私はAngularの問題だと思う。 GitHubのチケットは"beef up $resource futures"になります。本当に必要なのは、あなたが持っているリソースの約束オブジェクトへのアクセスだからです。

または、ウォッチャーは、約束が解決されるまで待つことができます。

一方、タイムアウトを必要としないこれを修正するもう少しエレガントな方法は、成功したコールバックから監視されているスコーププロパティを$リソースに再割り当てすることです。これにより、ウォッチャーは適切なタイミングで再び発射されます。

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

例:

$scope.myAttr = MyResource.fetch(
    function (resource) { $scope.myAttr = new MyResource(angular.copy(resource)); } 
); 
4

この問題もありました。私の変数は、最初はスコープ内で '定義されていません'と定義されていなかったからです。ウォッチは未定義の変数では機能しないようです。結局明白なようだ。

私は最初に、自分の変数がコントローラーによって効果的に設定されるときに、ウォッチを使用して時計を使用しようとしました。例:私はサービスを呼び出す前に、空のオブジェクトと私の変数を初期化することによってそれを解決し

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 = {}; 
}); 
}); 

その場合の時計では、変数の変化を検出することができました。

関連する問題