programing

WebAPI를 사용한 ng-grid에 대한 서버측 페이징+필터링+정렬

mailnote 2023. 10. 23. 22:01
반응형

WebAPI를 사용한 ng-grid에 대한 서버측 페이징+필터링+정렬

저는 ASP와 함께 ng-grid를 사용하는 간단한 작업 예시를 만들기 위해 노력하고 있습니다.NET Web API.그래서 ng-grid 예제 페이지(http://angular-ui.github.io/ng-grid/); 에서 서버측 페이징 예제부터 시작했습니다. 디버깅을 할 때 데이터가 제대로 수신되는지 확인할 수 있더라도 그리드에는 항상 빈 열이 표시됩니다.아마 그리드 설정에서 뭔가를 놓치고 있는 것 같지만, 제가 찾은 샘플들은 모두 제 것과 비슷해 보입니다.누가 도와줄 수 있습니까?제가 한 일은 이렇습니다.

업데이트 #1: 제안된 해결책은 첫 페이지에 대해서만 작동하는 것 같습니다.새 페이지로 이동하거나 새로 고침이 필요한 다른 작업을 수행할 때마다 서버가 예상대로 데이터 변경 내용을 반환하더라도 표시되는 데이터는 그대로 유지됩니다.또한 모든 코드 샘플에서 데이터를 다시 비우고 채우는 것보다는 단순히 어레이 멤버 값을 대체하는 것이 올바른 설정 방법인 것 같습니다.https://groups.google.com/forum/ #!searchin/angular/nggrid/angular/vUIfHWt4s_4/oU_C9w8j-uMJ에서 제안한 대로 apply를 시도했지만 결과는 같습니다.


서버측

새로운 MVC4 앱을 만들고 NuGet 패키지를 업데이트하고 각도 및 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()
                   };
    }
}

고객측

클라이언트 측면에서 제 각진 앱은 ng-grid 샘플을 모델로 한 단일 컨트롤러일 뿐입니다. 따라서 실제 시나리오에서는 모델(아마도 TypeScript 클래스에서 생성된)을 사용하고 싶어도 $scope에 속성을 직접 추가합니다.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의 모든 반환 항목을 탐색할 수 있습니다.하지만 그리드에는 아무것도 표시되지 않습니다.콘솔에 오류가 나타나지 않습니다.

조금 실험해보니 코드가 맞는 것 같습니다.apply 달러에 대한 이 게시물은 저에게 약간의 도움이 되었습니다: http://jimhoskins.com/2012/12/17/angularjs-and-apply.html .사실, 제 데이터가 이미 제공되는 $http에서 나온다는 점을 잘 이해한다면, 지원 전화가 필요하지 않을 것입니다.그래서 성공 콜백에서 범위 항목 변수를 설정하는 것으로 마쳤습니다.여기 또 완전체 JS가 있어요, 저 같은 새로운 사람에게 도움이 되길 바랍니다.이제 TypeScript 모델, 서비스 및 모든 실세계적인 것들로 테스트를 확장해 보겠습니다.새로운 게시물을 만들어야 할 것 같아요.. :)

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: "id", displayName: "ID", width: "60" },
            { 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 sb = [];
            for (var i = 0; i < $scope.sortOptions.fields.length; i++) {
                sb.push($scope.sortOptions.directions[i] === "DESC" ? "-" : "+");
                sb.push($scope.sortOptions.fields[i]);
            }

            var p = {
                name: $scope.filterOptions.filterText,
                pageNumber: $scope.pagingOptions.currentPage,
                pageSize: $scope.pagingOptions.pageSize,
                sortInfo: sb.join("")
            };

            $http({
                url: "/api/item",
                method: "GET",
                params: p
            }).success(function(data, status, headers, config) {
                $scope.totalServerItems = data.totalItems;
                $scope.items = data.items;
            }).error(function(data, status, headers, config) {
                alert(JSON.stringify(data));
            });
        }, 100);
    };

    // watches
    $scope.$watch('pagingOptions', function (newVal, oldVal) {
        if (newVal !== oldVal) {
            $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();
}]);

참고로, 코드를 보면 필드와 방향에 대한 배열이 두 개가 아니라 정렬 데이터에 대한 문자열 하나를 전달하고 있음을 알 수 있습니다.실제로 C# 컨트롤러에서 입력 모델의 멤버로 배열을 수신하는 올바른 방법을 찾을 수 없었기 때문에 각 필드 이름에 오름/하강 방향에 따라 + 또는 -가 붙여지는 하나의 문자열을 전달하는 것입니다.

ng-grid의 데이터 소스를 다음으로 설정합니다.items그러면 서버 성공 콜백에서 항목 배열을 업데이트하지 않습니다.

콜백이 성공하면 다음과 같은 작업을 수행합니다.

$scope.totalServerItems = data.totalItems;
angular.forEach(data.items, function(item) {
   $scope.items.push(item);
});

그것도 도움이 될 것입니다.

HTML 코드 샘플

<html ng-app="myApp">  
    <head lang="en">
        <meta charset="utf-8">
        <title>Getting Started With ngGrid code-sample</title>  
        <script type="text/javascript" src="angular.js"></script>
        <script type="text/javascript" src="ng-grid-1.3.2.js"></script>
    </head>
    <body ng-controller="MyCtrl">
        <div class="gridStyle" ng-grid="gridOptions"></div>
    </body>
</html>

AngulaJs 코드 샘플

var app = angular.module('myApp', ['ngGrid']);
app.controller('MyCtrl', function($scope, $http) {
    $scope.filterOptions = {
        filterText: "",
        useExternalFilter: true
    }; 
    $scope.totalServerItems = 0;
    $scope.pagingOptions = {
        pageSizes: [250, 500, 1000],
        pageSize: 250,
        currentPage: 1
    };  
    $scope.setPagingData = function(data, page, pageSize){  
        var pagedData = data.slice((page - 1) * pageSize, page * pageSize);
        $scope.myData = pagedData;
        $scope.totalServerItems = data.length;
        if (!$scope.$$phase) {
            $scope.$apply();
        }
    };
    $scope.getPagedDataAsync = function (pageSize, page, searchText) {
        setTimeout(function () {
            var data;
            if (searchText) {
                var ft = searchText.toLowerCase();
                $http.get('jsonFiles/largeLoad.json').success(function (largeLoad) {        
                    data = largeLoad.filter(function(item) {
                        return JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
                    });
                    $scope.setPagingData(data,page,pageSize);
                });            
            } else {
                $http.get('jsonFiles/largeLoad.json').success(function (largeLoad) {
                    $scope.setPagingData(largeLoad,page,pageSize);
                });
            }
        }, 100);
    };

    $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);

    $scope.$watch('pagingOptions', function (newVal, oldVal) {
        if (newVal !== oldVal && newVal.currentPage !== oldVal.currentPage) {
          $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
        }
    }, true);
    $scope.$watch('filterOptions', function (newVal, oldVal) {
        if (newVal !== oldVal) {
          $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
        }
    }, true);

    $scope.gridOptions = {
        data: 'myData',
        enablePaging: true,
        showFooter: true,
        totalServerItems: 'totalServerItems',
        pagingOptions: $scope.pagingOptions,
        filterOptions: $scope.filterOptions
    };
});

마지막 문서는 이 질문에 대해 매우 명확합니다. http://ui-grid.info/docs/ #/ tutorial/308_external_

내 결과 코드:

var pagination = {
    pageNumber: 1,
    pageSize: 10,
    // list fields to be sorted
    sort: [{field:'dup_percentage', direction:'desc'}],
    // list fields to be filtered
    filter: []
};

$scope.gridOptions = {
    enableFiltering: true,
    useExternalFiltering: true,
    columnDefs: [...],
    onRegisterApi: function( gridApi ) {
        $scope.gridApi = gridApi;
        $scope.gridApi.core.on.filterChanged( $scope, function() 
        {
                var grid = this.grid;

                // reset filters
                pagination.filter = [];

                // loop over all columns
                angular.forEach(grid.columns, function(column, i)
                {
                    // loop over filters
                    if(typeof column.filters!==undefined)
                    {
                        angular.forEach(column.filters, function(filter, j)
                        {
                            // add column name and value to filter array
                            // to be send server side
                            if(typeof filter.term!=undefined && filter.term!==undefined)
                            {
                                //console.log('add filter', {column:column.name, search:filter.term});
                                pagination.filter.push({column:column.name, search:filter.term});
                            }
                        });
                    }
                });


                // when user types it's search term
                // server would be hitting too much 
                // so we add 500ms throttle
                if (angular.isDefined($scope.filterTimeout))
                {
                    $timeout.cancel($scope.filterTimeout);
                }
                $scope.filterTimeout = $timeout(function () 
                {
                    // use pagination var which contains all info
                    // needed server side
                    getPage();
                }, 500);
            });

이제 클라이언트 쪽은 끝났습니다! 서버 쪽으로 처리하셔야 합니다. 도와드릴 수 없습니다.PHP/Mysql 구동 중이므로 Net WebAPI...

저는 최근 ng-grid와 함께 일하고 있습니다.AngularJS의 새로운 버전을 참고하던 중에 비슷한 문제가 생겼습니다.각도 min 파일 1.0.2를 참조하고 있는지 확인합니다.

여기 ng-grid with pagination에 대한 제 클라이언트 사이드 코드가 있습니다.Angular JS의 적절한 버전을 구현하면 완벽하게 작동합니다.

var app = angular.module('myApp', ['ngGrid']);

app.controller('MyCtrl', function ($scope, $http) {
// We needed to bring back mer becase we were using a variable that was being reassigned later on
var mer = [{ Item: "Bottle", Pcode: 50, OHQ: 333, AQ: 33, Details: "CLICK" },
    { Item: "Bottle", Pcode: 43, OHQ: 2350, AQ: 1250, Details: "CLICK" },
    { Item: "Bottle", Pcode: 27, OHQ: 4000, AQ: 3000, Details: "CLICK" },
    { Item: "Bottle", Pcode: 29, OHQ: 55, AQ: 10, Details: "CLICK" },
    { Item: "Bottle", Pcode: 34, OHQ: 27, AQ: 2, Details: "CLICK" },
    { Item: "Bottle", Pcode: 50, OHQ: 111, AQ: 33, Details: "CLICK" },
    { Item: "Bottle", Pcode: 43, OHQ: 123, AQ: 1250, Details: "CLICK" },
    { Item: "Bottle", Pcode: 27, OHQ: 1234, AQ: 3000, Details: "CLICK" },
    { Item: "Bottle", Pcode: 29, OHQ: 5678, AQ: 10, Details: "CLICK" },
    { Item: "Bottle", Pcode: 34, OHQ: 0, AQ: 2, Details: "CLICK" }];


$scope.filterOptions = {
    filterText: "",
    useExternalFilter: false
};
$scope.totalServerItems = 0;
$scope.pagingOptions = {
    pageSizes: [5, 10],
    pageSize: 5,
    currentPage: 1
};

$scope.setPagingData = function (data, page, pageSize) {
    var pagedData = data.slice((page - 1) * pageSize, page * pageSize);
    $scope.myData = pagedData;
    $scope.totalServerItems = data.length;
    if (!$scope.$$phase) {
        $scope.$apply();
    }
};

// I rearranged some of the code in this function.  I noticed we were calling the same function
// in the end just with a slightly different set of data....so instead of having 18-ish lines of code
// we have 12 (YAY)
$scope.getPagedDataAsync = function (pageSize, page, searchText) {
    setTimeout(function () {
        var data = mer;
        if (searchText) {
            var ft = searchText.toLowerCase();
            data = mer.filter(function (item) {
                JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
            });
        }
        $scope.setPagingData(data, page, pageSize);
    }, 100);
};

$scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);

$scope.$watch('pagingOptions', function (newVal, oldVal) {
    // Got rid of the other check here...this is what was causing the filter to not change the data when it changed.
    if (newVal !== oldVal) {
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
    }
}, true);

$scope.$watch('filterOptions', function (newVal, oldVal) {
    if (newVal !== oldVal) {
        $scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage, $scope.filterOptions.filterText);
    }
}, true);

$scope.gridOptions = {
    data: 'myData',
    enablePaging: true,
    showFooter: true,
    totalServerItems: 'totalServerItems',
    pagingOptions: $scope.pagingOptions,
    filterOptions: $scope.filterOptions
};

});

Angular 웹사이트의 샘플처럼 하기만 하면 됩니다.

$http({
            url: "/payments/GetPayments",
            method: "GET",
            params: p
        }).success(function(data, status, headers, config) {
            // Как в примере
            $scope.items = data.items;
            $scope.totalServerItems = data.totalItems;
            if (!$scope.$$phase) {
                $scope.$apply();
            }

        }).error(function(data, status, headers, config) {
                alert(JSON.stringify(data));
        });

언급URL : https://stackoverflow.com/questions/17786091/server-side-pagingfilteringsorting-for-ng-grid-with-webapi

반응형

'programing' 카테고리의 다른 글

정수 대 IP 주소 - C  (0) 2023.10.23
서명되지 않은 MySQL TINYINT  (0) 2023.10.23
시퀀스 캐시 및 성능  (0) 2023.10.23
Powershell: XML을 문자열로 변환  (0) 2023.10.23
ASP를 사용하는 기본 AJAX 예제.NET MVC?  (0) 2023.10.23