Как использовать Angular 1.6.5 вызов $http-запроса рекурсивно, когда возвращаемый набор данных ограничен
Я хотел бы использовать Angular 1.6.5 для перестройки проекта, но я не уверен, как использовать запрос $http.get на фабрике, когда источник возвращает только ограниченное количество записей за раз (1000 возвращается на запрос) и есть более 2000 записей, которые мне нужно получить.
В моем текущем коде я использую jquery ajax, а в методе.done проверяю наличие значения "__next", и, если оно существует, я вызываю функцию, передающую значение "__next". Когда значение "__next" не возвращается, я что-то делаю с данными.
function getSpecifiedList(url){
var specUrl = url;
$.ajax({
url: specUrl,
type: "GET",
headers:{"accept":"application/json;odata=verbose",
error: function(xhr){
console.log(xhr.status + " " + xhr.statusText);
}
}
}).done(function (results){
$("#wc_report_holder").text(results.length);
//buildObjects processes the results and adds to an array
buildObject(results);
if(results.d.__next){
getSpecifiedList(results.d.__next);
}else{
buildGridView();
}
}).fail(function(error){
$("#wc_report_holder").text("There was an error: " + error);
});
}
Я хотел бы выяснить, как реализовать ту же проверку значений и рекурсивный вызов в angular 1.6.5, используя лучшие практики и наиболее эффективные, но мне не повезло, что я смог это выяснить на основе угловых документов и Google.
Вот краткая версия того, что я сейчас использую в Angular 1.6.5.
<script>
var sitesApp = angular.module("sitesApp", ['ngRoute']);
sitesApp.controller('SitesListCtrl', ['$scope', 'sites',
function ($scope, sites) {
sites.list().then(function (response) {
$scope.sites = response.data.value;
});
}
]);
sitesApp.controller("SiteDetailsCtrl", ['$scope', '$routeParams', 'sites',
function ($scope, $routeParams, sites) {
sites.find($routeParams.SiteCodePc, function (site) {
$scope.site = site;
});
}
]);
sitesApp.config(function ($routeProvider, $locationProvider) {
$locationProvider.hashPrefix('!');
$routeProvider.
when('/', {
templateUrl: 'https://machine/sites/site-list.html',
controller: 'SitesListCtrl'
}).
when('/:SiteCodePc', {
templateUrl: 'https://machine/sites/site-details.html',
controller: 'SiteDetailsCtrl'
}).
otherwise({
redirectTo: '/'
});
});
sitesApp.factory('sites', ['$http', function ($http) {
var urlBase = "https://some-endpoint-for-data";
var cachedData;
function getData(callback) {
if (cachedData) {
callback(cachedData);
} else {
return $http({
method: 'GET',
url: urlBase
})
.then(function (response) {
//HERE IS WHERE I THINK THE SOLUTION NEEDS TO BE IMPLEMENTED
cachedData = response;
return cachedData;
});
}
}
return {
list: getData,
find: function (SiteCodePc, callback) {
getData(function (response) {
var site = response.data.value.filter(function (entry) {
//debugger;
return entry.SiteCodePc === SiteCodePc;
});
callback(site[0]);
});
}
};
}]);
</script>
<div ng-app="sitesApp">
<div ng-view></div>
</div>
заранее спасибо
2 ответа
Похоже, вы можете сделать простую рекурсию, где вы принимаете второй (необязательный) параметр. Если вы вызываете getData() в первый раз, вы можете получить свои первые 1000 результатов. Однако, если вы найдете __next, то вы будете вызывать его снова, посылая текущие 1000 результатов, которые у вас есть, и сопоставлять следующие 1000 результатов с предыдущими 1000.
sitesApp.factory('sites', ['$http', function ($http) {
var urlBase = "https://some-endpoint-for-data";
function getData(callback, results) {
return $http({
method: 'GET',
url: urlBase
})
.then(function (response) {
// If you have found a previous batch of results then concat the two arrays
if(results) {
response = response.concat(results);
}
// If there are more results to be found then recursively call the same function passing the batched results
if(response.__next) {
return getData(callback, response);
}
// If there are no more results to be found then trigger your callback function
else {
callback(response);
}
});
}
return {
list: getData,
find: function (SiteCodePc, callback) {
getData(function (response) {
var site = response.data.value.filter(function (entry) {
//debugger;
return entry.SiteCodePc === SiteCodePc;
});
callback(site[0]);
});
}
};
}]);
Я реализовал такой же сценарий с логикой пагинации и $ q. В этом примере кода я рекурсивно извлекаю записи как ленивые на основе LazyloadingLimit. Вы можете указать лимит на основе ваших требований. Таким образом, он извлекает записи только на основе количества из общего сбора. В этом примере ниже я не использую $ http. На вашем реальном примере вы можете использовать $http, чтобы получить записи с сервера. Здесь я просто жестко закодировал коллекцию изначально.
В вашем случае вы должны сначала получить общее количество записей и применить некоторую логику разбиения на страницы или какой-либо другой параметр для получения следующих записей.
angular.module('app', []);
angular.module('app').controller('SampleController', function ($scope,$http, $timeout, $q) {
// $scope.initialize();
$scope.mainCount = 0;
$scope.lazyloadingLimit = 2;
$scope.tileDefinitions = null;
$scope.tempList = null;
$scope.totalRecordCollection = [
{ "Name": "Record1" },
{ "Name": "Record2" },
{ "Name": "Record3" },
{ "Name": "Record4" },
{ "Name": "Record5" },
{ "Name": "Record6" },
{ "Name": "Record7" },
];
function getTotalRecordCollection() {
var deferred = $q.defer();
deferred.resolve($scope.totalRecordCollection);
return deferred.promise;
}
$scope.initialize = function () {
debugger;
var currentCount=0;
var pageList = new Array();
var currentPage = 1;
var numberPerPage = 2;
var numberOfPages = 0;
function makeList() {
numberOfPages = getNumberOfPages();
}
function getNumberOfPages() {
return Math.ceil($scope.tempList.length / numberPerPage);
}
function nextPage() {
currentPage += 1;
}
function loadList() {
var deferred = $q.defer();
if (currentCount !== $scope.tempList.length) {
var begin = ((currentPage - 1) * numberPerPage);
var end = begin + numberPerPage;
pageList = $scope.tempList.slice(begin, end);
currentCount = currentCount + pageList.length;
$scope.mainCount = currentCount;
deferred.resolve(true);
} else {
debugger;
return $q.reject();
}
return deferred.promise;
}
function loadNextRecords() {
loadList().then(function (res) {
nextPage();
loadNextRecords();
});
}
getTotalRecordCollection().then(function (response) {
debugger;
$scope.tempList = response;
makeList();
loadNextRecords();
});
}
});
<body ng-controller="SampleController">
<input type="button" value="Click Here" ng-click="initialize()"/>
{{mainCount}}
</body>
Как только все записи загружены, вы должны отклонить обещание, иначе рекурсивные циклы никогда не заканчиваются.
Надеюсь это поможет