12

tl:dr

ajax/jsonを使用して「select」フィルタを含むng-tableにデータを入力するにはどうすればよいですか?

問題を示すプランク: http://plnkr.co/Zn09LV


詳細

私は AngualrJS と ng-table 拡張機能を理解しようとしていますが、実際のデータをロードしようとすると、javascript で定義された静的データを使用しているときに、フィルターなどを使用していくつかの素敵なテーブルを取得できます。ひっかかったテーブル。

ng-table の本体は正しく入力されており、テキスト フィルターのみを使用している限り、すべてが機能しているようです。

        <td data-title="'Name'" filter="{ 'Name': 'text' }" sortable="'Name'">
            {{user.Name}}
        </td>

うまく動作します。

ただし、選択フィルターを使用するようにこれを更新すると、次のようになります。

        <td data-title="'Name'" filter="{ 'Name': 'select' }" sortable="'Name'"  filter-data="Names($column)">
            {{user.Name}}
        </td>

サーバーからデータが返される前に Names 変数が常に評価されるという同期の問題に遭遇しました。(おそらく、サーバーへのリクエストが送信される前に Names 変数が評価されます。) これは、フィルターの空のリストを取得することを意味します。

データがサーバーから返されると、選択フィルターを更新する方法が見つからないようです。最初にフィルター リストを作成するコードを再実行しても効果がないようです。更新された変数が読み取られないように、フィルターを再チェックするために ng-table をトリガーする方法がわかりません。また、非同期呼び出しが完了するまで変数の評価を延期する方法もわかりません。

私の JavaScript では、ng-table GitHub ページのサンプル ajax コードをほぼ使用し、そこに選択フィルターのサンプル コードを追加しました。

    $scope.tableParams = new ngTableParams({
        page: 1,            // show first page
        count: 10,          // count per page
        sorting: {
            name: 'asc'     // initial sorting
        }
    }, {
        total: 0,           // length of data
        getData: function($defer, params) {
            // ajax request to api
            Api.get(params.url(), function(data) {
                $timeout(function() {
                    // update table params
                    var orderedData = params.sorting ?
                    $filter('orderBy')(data.result, params.orderBy()) :
                    data.result;
                    orderedData = params.filter ?
                    $filter('filter')(orderedData, params.filter()) :
                    orderedData;

                    $scope.users = orderedData.slice((params.page() - 1) * params.count(), params.page() * params.count());

                    params.total(orderedData.length); // set total for recalc pagination
                    $defer.resolve($scope.users);
                }, 500);
            });
        }
    });

    var inArray = Array.prototype.indexOf ?
    function (val, arr) {
        return arr.indexOf(val)
    } :
    function (val, arr) {
        var i = arr.length;
        while (i--) {
            if (arr[i] === val) return i;
        }
        return -1
    };
$scope.names = function(column) {
    var def = $q.defer(),
        arr = [],
        names = [];
    angular.forEach(data, function(item){
        if (inArray(item.name, arr) === -1) {
            arr.push(item.name);
            names.push({
                'id': item.name,
                'title': item.name
            });
        }
    });
    def.resolve(names);
    return def;
};

追加の $q.defer() を追加し、最初のデータをラップしてから $scope.names 関数を実行する試みをいくつか試みましたが、promise と defer についての私の理解は、何かを機能させるのに十分ではありません。

GitHub には、これが ng-table のバグであることを示唆するメモがいくつかありますが、それが事実なのか、それとも何か馬鹿げたことをしているだけなのかはわかりません。

https://github.com/esvit/ng-table/issues/186

手続き方法についての指針は非常に高く評価されています

-カイネ-

4

8 に答える 8

8

同様の、しかし少し複雑な問題がありました。フィルターのリストを動的に更新できるようにしたかったのですが、とにかく $scope 変数に入れる必要があるため、完全に実行可能に見えました。基本的に、私が持っていれば、$scope.filterOptions = [];設定できfilter-data="filterOptions"、そのリストへの更新が自動的に反映されることを期待していました。私は間違っていた。

しかし、私はかなり良いと思う解決策を見つけました。まず、ngTable 選択フィルター テンプレートをオーバーライドする必要があります (これを行う方法がわからない場合は、それを使用$templateCacheする必要があり、オーバーライドする必要があるキーは です'ng-table/filters/select.html')。

通常のテンプレートでは、このようなものが見つかりますが、これng-options="data.id as data.title for data in $column.data"の問題$column.dataは、更新時に変更されない固定値であること$scope.filterOptionsです。

私の解決策は、オプションのリスト全体を渡すのではなく、フィルター データとして$scopeキーのみを渡すことです。そのため、 の代わりに をfilter-data="filterOptions"渡しfilter-data="'filterOptions'"、次のようにテンプレートに小さな変更を加えますng-options="data.id as data.title for data in {{$column.data}}"

明らかに、これは選択フィルターの動作に対する重要な変更です。私の場合は、テーブルが 1 つしかない非常に小さなアプリでしたが、このような変更によって他の選択が壊れるのではないかと心配するかもしれません。その場合は、「select」をオーバーライドするだけでなく、このソリューションをカスタム フィルターに組み込むことをお勧めします。

于 2015-08-31T05:21:24.480 に答える
4

これは私のために働く:

HTML:

<td data-title="'Doc type'" filter="{ 'doc_types': 'select' }" filter-data="docTypes()" sortable="'doc_types'">
    {{task.doc_type}}
</td>

AngularJS:

$scope.docTypes = function ($scope) 
{
    var def = $q.defer();
    //var docType = [
    //    {'id':'4', 'title':'Whatever 1'},
    //    {'id':'9', 'title':'Whatever 2'},
    //    {'id':'11', 'title':'Whatever 3'}
    //];

    // Or get data from API.
    // Format should be same as above.
    var docType = $http.get('http://whatever.dev', {
        params: { param1: data1 }
    });

    //Or with Restangular 
    var docType = Restangular.all('/api/doctype').getList();

    def.resolve(docType);
    return def;
};
于 2014-06-27T10:55:08.930 に答える
3

@Andiónが述べたように、カスタムフィルターで達成できます。

Promises ( Angular の $q サービス)を使用すると、非同期データ ポピュレーションを簡単に達成できます。Promisesに関する興味深いAndy の記事

$scope.names メソッドを修正し、非同期データを返し、遅延オブジェクトを次のように解決する $http サービスを追加できます。

$scope.names = function(column) {
  var def = $q.defer();

  /* http service is based on $q service */
  $http({
    url: siteurl + "app/application/fetchSomeList",
    method: "POST",

  }).success(function(data) {

    var arr = [],
      names = [];

    angular.forEach(data, function(item) {
      if (inArray(item.name, arr) === -1) {
        arr.push(item.name);
        names.push({
          'id': item.name,
          'title': item.name
        });
      }
    });
    
    /* whenever the data is available it resolves the object*/
    def.resolve(names);

  });

  return def;
};

于 2014-10-15T02:39:52.140 に答える
2

同様の問題が発生しましたが、フィルター値を取得するために追加の AJAX 呼び出しを行いたくありませんでした。

OP のコードの問題は、 $scope.data が入力される前に filter-data 関数が実行されることです。これを回避するために、Angular の $watch を使用して $scope.data の変更をリッスンしました。$scope.data が有効になると、filter-data が正しく設定されます。

        $scope.names2 = function () {
        var def = $q.defer(),
             arr = [],
                names = [];
        $scope.data = "";
        $scope.$watch('data', function () {


            angular.forEach($scope.data, function (item) {
                if (inArray(item.name, arr) === -1) {
                    arr.push(item.name);
                    names.push({
                        'id': item.name,
                        'title': item.name
                    });
                }
            });

        });
        def.resolve(names);
        return def;
    };

元のプランクは変更で分岐しました: http://plnkr.co/edit/SJXvpPQR2ZiYaSYavbQA

$watch に関するこの SO の質問も参照してください: How do I use $scope.$watch and $scope.$apply in AngularJS?

于 2015-01-30T20:59:09.390 に答える
0

「まず、ngTable 選択フィルター テンプレートをオーバーライドする必要があります (これを行う方法がわからない場合は、$templateCache を使用する必要があり、オーバーライドする必要があるキーは 'ng-table/filters/select.html' です)。 ."

ng-table のスクリプトの下にオーバーライドされたスクリプトを追加すると、すべてうまくいきました...

<script id="ng-table/filters/select.html" type="text/ng-template">
 <select ng-options="data.id as data.title for data in {{$column.data}}" ng-table-select-filter-ds="$column" ng-disabled="$filterRow.disabled" ng-model="params.filter()[name]" class="filter filter-select form-control" name="{{name}}"> <option style="display:none" value=""></option> </select>
</script>
于 2017-01-10T08:25:11.673 に答える