Я пытаюсь создать простой рабочий пример использования ng-grid с ASP.NET WebAPI. Таким образом, я начал с примера подкачки на стороне сервера на странице примеров ng-grid (http://angular-ui.github.io/ng-grid/); так или иначе, моя сетка всегда показывает пустые столбцы, даже если при отладке я могу подтвердить, что данные получены правильно. Вероятно, я просто пропустил что-то в настройке сетки, но все образцы, которые я нашел, выглядят похожими на мои. Может ли кто-нибудь помочь? Вот что я сделал:
Обновление # 1: предлагаемое решение, похоже, работает, но только для первой страницы. Всякий раз, когда я перехожу на новую страницу или выполняю любую другую операцию, требующую обновления, отображаемые данные остаются неизменными, даже если сервер возвратит данные, как ожидалось. Кроме того, из всех образцов кода, которые я нашел, кажется, что правильный способ настройки данных - это просто заменить значение члена массива, а не опорожнять его и снова заполнять. Я попробовал применить, как предлагается в https://groups.google.com/forum/#!searchin/angular/nggrid/angular/vUIfHWt4s_4/oU_C9w8j-uMJ, но я получаю тот же результат.
Серверная сторона
Просто создайте новое приложение MVC4, обновите пакеты NuGet и добавьте пакеты angular и ng-grid. Моя поддельная модель данных представлена классом Item:
public sealed class Item
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public bool IsFemale { get; set; }
}
Я также добавляю пару моделей для обработки пейджинга, фильтрации и сортировки различных наборов данных (мне легче найти общую базовую модель подкачки -PagedFilter- и ряд производных моделей):
public class PagedFilter
{
private int _nPageSize;
private int _nPageNumber;
public int PageSize
{
get { return _nPageSize; }
set
{
if (value < 1) throw new ArgumentOutOfRangeException("value");
_nPageSize = value;
}
}
public int PageNumber
{
get { return _nPageNumber; }
set
{
if (value < 1) throw new ArgumentOutOfRangeException("value");
_nPageNumber = value;
}
}
public int TotalItems { get; set; }
public int TotalPages
{
get { return (int)Math.Ceiling((double)(TotalItems / PageSize)); }
}
public PagedFilter()
{
_nPageSize = 20;
_nPageNumber = 1;
}
}
Вот ItemFilter:
public class ItemFilter : PagedFilter
{
public List<string> SortFields { get; set; }
public List<string> SortDirections { get; set; }
public string Name { get; set; }
public int? MinAge { get; set; }
public int? MaxAge { get; set; }
}
Затем я добавляю контроллер API для получения элементов:
public class ItemController : ApiController
{
// fake data
private readonly List<Item> _items;
public ItemController()
{
Random rnd = new Random();
_items = new List<Item>();
char c = 'a';
for (int i = 0; i < 1000; i++)
{
_items.Add(new Item
{
Id = i,
Age = rnd.Next(1, 100),
IsFemale = ((i & 1) == 0),
Name = String.Format(CultureInfo.InvariantCulture, "{0:00000}-{1}",
i, new string(c, 5))
});
if (++c > 'z') c = 'a';
}
}
public dynamic Get([FromUri] ItemFilter filter)
{
var items = _items.AsQueryable();
// filtering
if (!String.IsNullOrEmpty(filter.Name))
items = items.Where(i => i.Name.Contains(filter.Name));
if (filter.MinAge.HasValue)
items = items.Where(i => i.Age >= filter.MinAge.Value);
if (filter.MaxAge.HasValue)
items = items.Where(i => i.Age <= filter.MaxAge.Value);
// ...sorting (using Dynamic Linq) omitted for brevity...
// paging
int nTotalItems = items.Count();
items = items.Skip((filter.PageNumber - 1) * filter.PageSize)
.Take(filter.PageSize);
return new
{
totalItems = nTotalItems,
items = items.ToArray()
};
}
}
Клиентская сторона
На стороне клиента мое приложение angular - это всего лишь один контроллер, смоделированный по образцу ng-grid: таким образом, я напрямую добавляю свойства в область $scope, даже если в реальном сценарии я предпочел бы использовать модель (вероятно, сгенерированный из класса TypeScript). HTML:
<div ng-app="MyApp" ng-controller="MainController">
<div ng-grid="gridOptions" style="height: 400px">
</div>
</div>
JS:
var app = angular.module('MyApp', ['ngGrid']);
app.controller('MainController', ['$scope', '$http', function ($scope, $http, $apply) {
$scope.items = [];
// filter
$scope.filterOptions = {
filterText: "",
useExternalFilter: true
};
// paging
$scope.totalServerItems = 0;
$scope.pagingOptions = {
pageSizes: [25, 50, 100],
pageSize: 25,
currentPage: 1
};
// sort
$scope.sortOptions = {
fields: ["name"],
directions: ["ASC"]
};
// grid
$scope.gridOptions = {
data: "items",
columnDefs: [
{ field: "name", displayName: "Name", pinnable: true },
{ field: "age", displayName: "Age", width: "60" },
{ field: "isFemale", displayName: "F", width: "40" }
],
enablePaging: true,
enablePinning: true,
pagingOptions: $scope.pagingOptions,
filterOptions: $scope.filterOptions,
keepLastSelected: true,
multiSelect: false,
showColumnMenu: true,
showFilter: true,
showGroupPanel: true,
showFooter: true,
sortInfo: $scope.sortOptions,
totalServerItems: "totalServerItems",
useExternalSorting: true,
i18n: "en"
};
$scope.refresh = function() {
setTimeout(function () {
var p = {
name: $scope.filterOptions.filterText,
pageNumber: $scope.pagingOptions.currentPage,
pageSize: $scope.pagingOptions.pageSize,
sortFields: $scope.sortOptions.fields,
sortDirections: $scope.sortOptions.directions
};
$http({
url: "/api/item",
method: "GET",
params: p
}).success(function(data, status, headers, config) {
$scope.totalServerItems = data.totalItems;
// SUGGESTION #1 -- empty and fill the array
/* $scope.items.length = 0;
angular.forEach(data.items, function (item) {
$scope.items.push(item);
});
*/
// https://groups.google.com/forum/#!searchin/angular/nggrid/angular/vUIfHWt4s_4/oU_C9w8j-uMJ
$scope.$apply(function () { $scope.items = data.items; });
if (!$scope.$$phase) {
$scope.$apply();
}
}).error(function(data, status, headers, config) {
alert(JSON.stringify(data));
});
}, 100);
};
// watches
$scope.$watch('pagingOptions', function (newVal, oldVal) {
if (newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
$scope.refresh();
}
}, true);
$scope.$watch('filterOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.refresh();
}
}, true);
$scope.$watch('sortOptions', function (newVal, oldVal) {
if (newVal !== oldVal) {
$scope.refresh();
}
}, true);
$scope.refresh();
}]);
В моем коде вызывается обратный вызов успеха, и я могу просматривать все возвращенные элементы в data.items. Тем не менее в сетке ничего не отображается. В консоли не появляется ошибка.