2013-06-05 15 views
67

コントローラでは、$ httpまたは$ resourceサービスを使用してJSONデータを取得します。次に、このデータを$ scopeに書き込み、AngularJSはページのHTML構造を更新します。私の問題は、角度のng-repeatディレクティブで埋められているリスト(HTML DOM要素)の新しいサイズ(幅と高さ)が何であるかを知る必要があることです。したがって、DOM構造を更新するAngularの終了直後にjavascriptコードを実行する必要があります。それを行う正しい方法は何ですか?私は過去4時間にわたってインターネットを検索しましたが、私の問題に対する解決策は見つかりませんでした。AngularJSがレンダリングを完了した後にjQueryコードを実行する

これは私がJSONデータを受信する方法である:

var tradesInfo = TradesInfo.get({}, function(data){ 
    console.log(data); 
    $scope.source.profile = data.profile; 
      $scope.trades = $scope.source.profile.trades; 
     $scope.activetrade = $scope.trades[0]; 
     $scope.ready = true; 


    init(); //I need to call this function after update is complete 

}); 

そして、これがinit()機能で何が起こるかです:

function init(){ 
    alert($('#wrapper').width()); 
    alert($('#wrapper').height()); 
} 

私はそこにこの問題を解決するための簡単なものになるが、私はすることができなければならないことを知っています今すぐ見つけてください。 ありがとうございます。

+0

をダイジェスト発生させずに$タイムアウトの使用方法へのリンクがdrzausします。ちょうど同じように。予期せぬ$ compile呼び出し、任意の数のディレクティブ、DOM自身を操作して$タイムアウトの後に行う設定をすることがあります... AngularJSシステムは美しく設計されているので、断片は独立して動作します。支払う。ちょうど別の方法を見つける。 – rewritten

+1

とにかくできると思います。私は、その命令でdomがコンパイル関数を呼び出すことができる、または予測できない他の何かがそれを防ぐことができないという事実、imhoを意味します。 – Dobby007

+0

古い質問を人生に持ち込んで申し訳ありませんが、#wrapperのコンテンツを共有できますか?おそらく、取引を繰り返すだけでしょうか? – FrEaKmAn

答えて

62

は、実はこのケースでは、角度の方法は、簡単な方法だけ正しい方法ではありません:)

あなたはディレクティブを書いて、あなたはの高さを知りたい要素にアタッチする必要があります。そしてあなたが$イベントを放送しているコントローラから、指示文がイベントを捕まえるでしょう。そこにDOM操作をすることができます。決してコントローラの中にいない。

var tradesInfo = TradesInfo.get({}, function(data){ 
    console.log(data); 
    $scope.source.profile = data.profile; 
    ... 

    $scope.$broadcast('dataloaded'); 
}); 


directive('heightStuff', ['$timeout', function ($timeout) { 
    return { 
     link: function ($scope, element, attrs) { 
      $scope.$on('dataloaded', function() { 
       $timeout(function() { // You might need this timeout to be sure its run after DOM render. 
        element.width() 
        element.height() 
       }, 0, false); 
      }) 
     } 
    }; 
}]); 
+0

ありがとうございます。できます。 0msのタイムアウトがなぜなら私になぜ説明できますか?私はそれを省略しようとしたので、この場合、幅と高さが間違っていたので私は尋ねています。タイムアウト機能のJavascriptの動作とは何ですか?別のスレッドでコードを実行していますか? – Dobby007

+0

いいえ、実際には他のスレッドはありません。その理由はブラウザがトリックを行う理由です。それらは、クロージャーでのみDOMリフローを実行します。したがって、要素のディメンションが必要な場合は、まだレンダリングされていないため、要素を持つことはできません。あなたは測定ルーチンの実行を延期しなければならず、0を伴うsetTimeoutがどこに来るのかを遅らせる必要があります。ブラウザには、現在のクロージャを実行し、すでにタイムアウトを登録した後に実行してください。非常に基本的な例:http://jsfiddle.net/Zmetser/VfTar/ – Oliver

+8

これは正しくありません。ブラウザーは、関連するスタイルプロパティにアクセスしようとするとすぐにブロックを再レンダリングします。このシナリオでは、一般的にsetTimeoutを呼び出す必要はありません。デモhttp://jsfiddle.net/SLTpE/を参照してください。しかし、AngularJSは別の方法で動作します。Angularは、ブラウザではなくモデルを変更したときに即時にDOMを更新しません。 – amakhrov

5

JQueryを使用するもう1つの提案。 ディレクティブで生成されたグリッドに対して、これを実行する必要がありました。私はグリッド内の特定の行にスクロールしたかったのです。ディレクティブで

['$timeout',function($timeout){ 
... 
$scope.$on('dataloaded', function() { 
      $timeout(function() { // You might need this timeout to be sure its run after DOM render. 
       $scope.scrollToPosition(); 
      }, 0, false); 
     }); 
     $scope.scrollToPosition = function() { 
      var rowpos = $('#row_' + $scope.selectedActionID, "#runGrid").position(); 
      var tablepost = $('table', "#runGrid").position(); 
      $('#runGrid').scrollTop(rowpos.top - tablepost.top); 
     } 

.directive('runGrid',['$timeout', function ($timeout) { 
     // This directive generates the grip of data 
     return { 
      restrict: 'E', //DOM Element 
      scope: { //define isolated scope 
       list: '=', //use the parent object 
       selected: "=" 
      }, 

      templateUrl: '/CampaignFlow/StaticContent/Runs/run.grid.0.0.0.0.htm', //HTML template URL 

      controller: ['$scope', function ($scope) { //the directive private controller, whith its private scope 
       //$scope.statusList = [{ data_1: 11, data_2: 12 }, { data_1: 21, data_2: 22 }, { data_1: 31, data_2: 32 }]; 
       //Controller contains sort functionallity 

       $scope.sort = { column: null, direction: 1 } 
       $scope.column = null; 
       $scope.direction = "asc"; 
       $scope.sortColumn = function (id) { 
        if(id!=$scope.column) { 
         $scope.column = id; 
         $scope.direction = "asc"; 
        } else { 
         $scope.column = null; 
        } 
       } 
       $scope.toggleDir = function() { 
        $scope.direction = ($scope.direction == "asc") ? "desc" : "asc"; 
       } 
       $scope.$emit('dataloaded'); 
      }] 


     }; 
    }]) 

そして、これは、グリッドディレクティブHTMLテンプレートの抜粋です:コントローラで

:$親コントローラに指令から放送するために発する使用

<div style="overflow-y:auto;height: 200px;" id="runGrid"> 
      <table class="table table-striped" style="table-layout:fixed"> 
      <tbody> 
       <tr ng-repeat="status in list" id="row_{{status.action_id}}" ng-class="(status.action_id==selected)?'selected':''"> 
        <td> 

リストと選択されたパラメータが、direを使用しているhtmlから注入されますctive

<run-grid list="list" selected="selectedActionID"></run-grid> 
6

オリバーの答えは良いですが、問題があります:あなたは、イベントをブロードキャストすることを忘れた場合、あなたのデータが変更された可能性がある一方で、あなたのjavascriptが実行されません。 別の解決策は、例えば、スコープの変更を監視するために、次のようになります。

var tradesInfo = TradesInfo.get({}, function(data) { 
    console.log(data); 
    $scope.profile = data.profile; 
    // ... 
}); 


directive('heightStuff', ['$timeout', 
    function($timeout) { 
    return { 
     scope: { 
     myData: '=' 
     }, 
     link: function($scope, element, attrs) { 
     $scope.$watch('myData', function() { 
      $timeout(function() { // You might need this timeout to be sure its run after DOM render. 
      element.width() 
      element.height() 
      }, 0, false); 
     }) 
     } 
    }; 
    } 
]); 
<div height-stuff my-data="profile"></div> 

javascriptの機能が毎回カスタムイベントを全く必要とせずにデータの変更と呼ばれているこの方法です。

3

これまでの回答では、ngRepeatの実行後に実行する必要があったコードが角度コードであるため、別の回答を追加したいと思います。その場合、上記のすべての回答はすばらしい単純な解決策ですダイジェストライフサイクルの重要な段階では、Ben Nadelのブログ($ evalの代わりに$ parseを使用しています)を見てみることができます。

私の経験では、OPの状態として、最終的にコンパイルされたDOMでいくつかのjQueryプラグインやメソッドが実行されています。この場合、最も簡単な解決策はsetTimeoutのディレクティブを作成することですsetTimeout関数は$タイムアウトを使用していない理由を不思議誰のために機能

angular.module('myApp', []) 
.directive('pluginNameOrWhatever', function() { 
    return function(scope, element, attrs) {   
    setTimeout(function doWork(){ 
     //jquery code and plugins 
    }, 0);   
    }; 
}); 

をpostLinkingその親の後に続けている通常ng-repeat、すべてが角度で行われた直後にその常に、ブラウザのキューの最後にプッシュされますそれは完全に不要な別のダイジェストサイクルを引き起こすということです。

EDIT:

ありがとうあなたがすることはできませんhttp://www.codelord.net/2015/10/14/angular-nitpicking-differences-between-timeout-and-settimeout/

+0

角度の['$ timeout'](https://docs.angularjs.org/api/ng/service/$ timeout) – drzaus

+0

私は最後の行で$ timeoutを使用しないと思う理由を書きました。もう一度お読みください。 – bresleveloper

+0

奇妙なことに、なぜ私はそれを見ていないのか分かりません。しかし、ダイジェストサイクルを望まない場合は、 'invokeApply = false'を呼び出すだけです。それ以外の場合、[lots]があります(http://stackoverflow.com/questions/19609796/what-advantage-is-there-in-using-the-timeout-in-angular-js-instead-of-window-se)[ (https://www.reddit.com/r/angularjs/comments/3gzb0d/timeout_vs_settimeout/)[引数](http://www.codelord.net/2015/10/14/angular-nitpicking-differences- between-timeout-and-settimeout /)を使って、 'setTimeout'を置き換えるためにAngularの開発者が書いたものを使いました。 – drzaus

関連する問題