How to populate select filters on ng-table from async call
如何使用ajax/json填充包含"select"过滤器的ng表?
Pluk显示问题:http://plnkr.co/zn09lv
细节我正在尝试处理angualrjs和ng表扩展,虽然我可以得到一些很好的带有工作过滤器的表,比如当我使用javascript中定义的静态数据时,一旦我试图将实际数据加载到表中,我就遇到了一个障碍。
ng表的主体是正确填充的,只要我只使用文本过滤器,一切都会正常工作:
1 2 3 | <td data-title="'Name'" filter="{ 'Name': 'text' }" sortable="'Name'"> {{user.Name}} </td> |
工作很好。
但是,如果我将此更新为使用选择筛选器:
1 2 3 | <td data-title="'Name'" filter="{ 'Name': 'select' }" sortable="'Name'" filter-data="Names($column)"> {{user.Name}} </td> |
我遇到了一个同步问题,即在从服务器返回数据之前,总是先评估name变量。(可能在向服务器发送请求之前对varibale的名称进行了评估。)这意味着我得到了一个空的过滤器列表。
一旦数据从服务器返回-我似乎找不到更新select过滤器的方法。重新运行最初创建过滤器列表的代码似乎没有任何效果-我不确定如何触发ng表来重新检查其过滤器,以便不读取更新的变量。在异步调用完成之前,我也找不到一种方法来推迟变量的计算。
对于我的javascript,我几乎使用了ng table github页面中的示例Ajax代码,并在其中添加了select过滤器的示例代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | $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表中的一个bug,但我不确定是否是这样,或者我只是在做一些愚蠢的事情。
https://github.com/esvit/ng-table/issues/186
关于如何继续大受赞赏的建议
-凯恩-
我有一个相似但稍微复杂的问题。我希望能够动态地更新过滤器列表,这看起来完全可行,因为无论如何它们应该只在$scope变量中。基本上,我希望,如果我有
但我找到了一个我认为很好的解决方案。首先,您需要覆盖ngtable select过滤器模板(如果您不知道如何做,它涉及使用
在普通模板中,您会发现类似于此
我的解决方案是只传递$scope键作为筛选数据,而不是传递整个选项列表。因此,我将通过
显然,这是对Select过滤器工作方式的重大更改。在我的例子中,这是一个只有一张表的非常小的应用程序,但是您可能会担心这样的更改会破坏您的其他选择。如果是这样,您可能希望将此解决方案构建到自定义筛选器中,而不只是重写"select"。
您可以通过自定义过滤器实现这一点:
表格上的标准选择过滤器代码显示:
1 2 3 4 5 | <select ng-options="data.id as data.title for data in column.data" ng-model="params.filter()[name]" ng-show="filter == 'select'" class="filter filter-select form-control" name="{{column.filterName}}"> </select> |
当您调用此数据时,您会传递:
为了避免这种情况,我在代码中做了一个快速的变通。编写自己的选择筛选器模板,如:
1 2 3 4 | <select id="filterTest" class="form-control" ng-model="tableParams.filter()['test']" ng-options="e.id as e.title for e in externaldata"> </select> |
在控制器中获取此外部数据:
1 | $scope.externaldata = Api.query(); // Your custom api call |
它工作得很好,但是我的数据上确实有一个
我知道这个解决方案不是最佳的。让我们看看是否有人在这里写的比这个"解决方法"更多,并启发我们。甚至埃斯维特有时也在这里;)
这对我很有用:
HTML:
1 2 3 | <td data-title="'Doc type'" filter="{ 'doc_types': 'select' }" filter-data="docTypes()" sortable="'doc_types'"> {{task.doc_type}} </td> |
AngularJS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $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; }; |
如@andi_n所述,您可以使用自定义过滤器来实现。
通过承诺(Angular中的$Q服务)很容易实现异步数据填充,这是安迪关于承诺的有趣文章。
您可以修改$scope.names方法并添加$http服务,该服务返回异步数据并将延迟对象解析为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | $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; }; |
我遇到了类似的问题,但不想进行额外的Ajax调用来获取过滤器值。
OP代码的问题在于,在填充$scope.data之前,过滤器数据函数会执行。为了解决这个问题,我使用角度$watch来监听$scope.data的变化。一旦$scope.data有效,就可以正确填充过滤器数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | $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; }; |
原始的Pluk随更改而分叉:http://plnkr.co/edit/sjxvppkr2ziyasyavbqa
也可以在$watch上看到这个问题:如何使用$scope.$watch和$scope.$apply在AngularJS中?
我用Diablo提到的$q.defer()解决了这个问题。
但是,IS代码实际上非常简单和简单:
在HTML中:
1 | <td ... filter-data="countries"> |
在控制器中:
1 2 3 4 | $scope.countries = $q.defer(); $http.get("/getCountries").then(function(resp){ $scope.countries.resolve(resp.data.data); }) |
我所做的只是将select标记与值放在一起,让ng模型返回过滤器的值。
这很有用,因为我需要翻译纯文本。
1 2 3 4 5 6 7 8 9 10 11 | <td data-title="'Status'| translate" ng-bind ="("cc_assignment_active"== '0') ? ('Inactive' | translate) : ('Active'| translate)" filter="{ cc_assignment_active: 'select3'}"> </td> <script id="ng-table/filters/select3.html" type="text/ng-template"> <select class="filter filter-select form-control" ng-model="params.filter()[name]" name="{{name}}"> <option active value="" translate>---All---</option> <option value="1" translate>Active</option> <option value="0" translate>Inactive</option> </select> |
"First, you need to override the ngTable select filter template (in case you don't know how to do this, it involves using $templateCache and the key you need to override is 'ng-table/filters/select.html')."
我在ng表的脚本下面添加了覆盖的脚本,一切都运行良好…
1 2 | <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> |