비동기 호출에서 ng-table의 선택 필터를 채우는 방법
-
21-12-2019 - |
문제
tl:dr
ajax/json을 사용하여 '선택' 필터를 포함하여 ng-table을 어떻게 채울 수 있나요?
문제를 보여주는 Plunk:http://plnkr.co/Zn09LV
세부 사항
나는 AngualrJS와 ng-table 확장을 이해하려고 노력하고 있습니다. 비록 작동하는 필터가 있는 멋진 테이블을 얻을 수 있지만 자바 스크립트에 정의된 정적 데이터를 사용할 때 - 일단 실제 데이터를 로드하려고 하면 내가 걸림돌을 쳤던 테이블.
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을 트리거하는 방법을 잘 모르겠습니다.또한 비동기 호출이 완료될 때까지 변수 평가를 연기하는 방법을 찾을 수 없습니다.
내 자바스크립트의 경우 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 함수로 래핑하는 시도를 몇 번 시도했지만 약속과 연기에 대한 이해가 제대로 작동하지 않을 만큼 강력하지 않습니다.
GitHub에는 이것이 ng-table의 버그라고 제안하는 몇 가지 메모가 있지만 그것이 사실인지 아니면 그냥 멍청한 일을 하고 있는지 확실하지 않습니다.
https://github.com/esvit/ng-table/issues/186
진행 방법에 대한 조언을 주셔서 감사합니다.
-케인-
해결책
비슷하지만 약간 더 복잡한 문제가 있었습니다.어쨌든 $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}}"
.
분명히 이것은 선택 필터의 작동 방식에 중요한 변화입니다.내 경우에는 테이블이 하나만 있는 아주 작은 앱에 대한 것이었지만 이와 같은 변경으로 인해 다른 선택이 중단될까 봐 걱정할 수도 있습니다.이 경우 'select'를 재정의하는 대신 이 솔루션을 사용자 지정 필터로 빌드할 수 있습니다.
다른 팁
당신은 그것을 달성할 수 있습니다 맞춤 필터:
그만큼 암호 ngtable의 표준 선택 필터에 대해 다음과 같이 말합니다.
<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>
이 데이터를 호출하면 다음을 전달합니다. filter-data="names($column)"
ngtable이 데이터 가져오기를 담당합니다.왜 이것이 외부 리소스에서 작동하지 않는지 모르겠습니다.나는 당신이 지적한 대로 $column 및 약속과 관련이 있다고 확신합니다.
이를 방지하기 위해 코드에서 빠른 해결 방법을 수행했습니다.다음과 같이 나만의 선택 필터 템플릿을 작성합니다.
<select id="filterTest" class="form-control"
ng-model="tableParams.filter()['test']"
ng-options="e.id as e.title for e in externaldata">
</select>
컨트롤러에서 이 외부 데이터를 가져옵니다.
$scope.externaldata = Api.query(); // Your custom api call
완벽하게 작동하지만 id
내 데이터에 있으므로 name
기능.
나는 이 솔루션이 최적이 아니라는 것을 이해합니다.누군가 여기에 이 '해결 방법'보다 더 많은 내용을 써서 우리에게 알려주는지 살펴보겠습니다.심지어 에스비트 가끔 여기 있어요 ;)
이것은 나를 위해 작동합니다 :
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;
};
. @ andión이 언급 한 바와 같이 "Nofollow"> 사용자 정의 필터 에서 얻을 수 있습니다.
약속을 가진 비동기 데이터 인구를 쉽게 달성하기 쉽습니다 ( 각 앵무새에서 $ Q 서비스), 흥미로운 Andy 기사 약속에 대한 / em>
$ 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;
};
.
비슷한 문제가 있었지만 필터 값을 가져 오기 위해 추가 Ajax 호출을 만들고 싶지는 않습니다.
OP의 코드의 문제는 $ scope.data가 채워지기 전에 필터 데이터 기능이 실행된다는 것입니다.이 문제를 해결하려면 Angular $ 워치를 사용하여 $ scope.data의 변경 사항을 수신합니다.$ scope.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/sjxvppqr2ziyasyavbqhqa
또한 $ watch에 대한 질문도 이것을 볼 수 있습니다 : $ scope을 어떻게 사용합니까?시계 및 $ Scope. Angularjs에 $ 적용
Diablo
가 언급 한 $ q.defer ()로 문제를 해결했습니다.그러나 실제로는 실제로 꽤 간단하고 간단합니다 :
html :
<td ... filter-data="countries">
.
컨트롤러 :
$scope.countries = $q.defer();
$http.get("/getCountries").then(function(resp){
$scope.countries.resolve(resp.data.data);
})
. "먼저 NGTable SELECT 필터 템플리트를 무시해야합니다 (이를 수행하는 방법을 모르는 경우, $ TEMPLATECACHE를 사용하는 것이 포함되며 재정의 해야하는 키는 'NG 테이블 / 필터 / 선택이 포함됩니다.html '). "
NG 테이블의 스크립트 아래에있는 무시 스크립트를 추가했으며 모든 것이 잘 작동했습니다 ...
<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>
. 내가 한 일은 선택 태그를 값으로 넣고 NG-Model이 필터의 값을 반환하게하는 것만으로 만드는 것입니다.
이것은 일반 텍스트를 번역 할 필요가 있으므로 도움이되었습니다.
<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>
.