diff --git a/README.md b/README.md index 30c62b2..b1dc410 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ -##Angular Data Grid +## Angular Data Grid + Light, flexible and performant Data Grid for AngularJS apps, with built-in sorting, pagination and filtering options, unified API for client-side and server-side data fetching, -seamless synchronization with browser address bar and total freedom in mark-up and styling suitable for your application. Angular 1.3 - 1.5 compliant. +seamless synchronization with browser address bar and total freedom in mark-up and styling suitable for your application. Angular 1.3 - 1.6 compliant. Demo Bootstrap: http://angular-data-grid.github.io/demo/bootstrap/ @@ -8,10 +9,15 @@ Demo Material: http://angular-data-grid.github.io/demo/material/ Demo 100k: http://angular-data-grid.github.io/demo/100k/ +Demo Angular UI Router: http://angular-data-grid.github.io/demo/bootstrap/ui-router.html + ### Features - Does not have any hard-coded template so you can choose any mark-up you need, from basic `` layout to any `
` structure. - Easily switch between the most popular Bootstrap and Google Material theming, or apply your own CSS theme just by changing several CSS classes. - - Built-in sync with browser address bar (URL), so you can copy-n-paste sorting/filtering/pagination results URL and open it in other browser / send to anyone - even if pagination / filtering are done on a client-side. + - Built-in sync with browser address bar (URL), so you can copy-n-paste sorting/filtering/pagination results URL and open it in other browser / send to anyone - even if pagination / filtering are done on a client-side. [See details](#url-synchronization) + - Support of [Angular UI Router](https://github.com/angular-ui/ui-router) navigation. + - Optional support of fixed header table: [Bootstrap Demo](http://angular-data-grid.github.io/demo/fixed-header/bootstrap-grid.html) [Material Design Demo](http://angular-data-grid.github.io/demo/fixed-header/angular-md-grid.html) + - Optional support of CSV data exports: [Demo](http://angular-data-grid.github.io/demo/bootstrap/) - Unlike most part of other Angular DataGrids, we intentionally use non-isolated scope of the directive to maximize flexibility, so it can be easily synchronized with any data changes inside your controller. NOTE! With great power comes great responsibility, so use non-isolated API wisely. @@ -87,7 +93,7 @@ angular.module('myApp', ['dataGrid', 'pagination']) }; ``` -NOTE: `grid-item` wrapper directive used in the example above, to make code more concise - you can use regular `ng-repeat` instead if needed. +NOTE: `grid-item` wrapper directive used in the example above, to make code more concise, but you can always use regular `ng-repeat` instead, like: `ng-repeat="item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage track by $index"` ### Basic API @@ -231,7 +237,18 @@ Then create in `gridOptions.customFilters` variable named as `ng-model` with fil ``` -### Others -All filters have optional parameter `disable-url`. If you set it to **true**, URL-synchronization for this filter will be disabled. +### URL Synchronization +You can disable/enable URL synchronization for the whole grid or on a level of particular filter. + +Global parameter `gridOptions.urlSync` (boolean, default is 'false') works for the whole grid. +Each filter has optional parameter `disable-url` (boolean, default is 'false'). If you set it to **true**, URL-synchronization for this particular filter will be disabled. + + +### Multiple grids on page If you need to use 2 or more grids on page, please add `id` to grids, and then use `grid-id` attribute on filters to specify their corresponding grid. [Example](http://angular-data-grid.github.io/demo/bootstrap/multiple.html) + +### Next / Future + - Migrate to Heroku + - Cover with unit / e2e tests + - Port to Angular2? diff --git a/demo/100k/index.html b/demo/100k/index.html index d16ea35..4ce1f28 100644 --- a/demo/100k/index.html +++ b/demo/100k/index.html @@ -207,14 +207,14 @@

Angular Data Grid 100k Example

- - - - - + + + + + - + \ No newline at end of file diff --git a/demo/100k/js/demoApp.js b/demo/100k/js/demoApp.js index 34bc386..47d6e5c 100644 --- a/demo/100k/js/demoApp.js +++ b/demo/100k/js/demoApp.js @@ -6,7 +6,10 @@ $scope.gridOptions = { data: [], - urlSync: true + urlSync: true, + pagination: { + itemsPerPage: '10' + } }; $http({ diff --git a/demo/bootstrap/index.html b/demo/bootstrap/index.html index 90b9860..ab4b483 100644 --- a/demo/bootstrap/index.html +++ b/demo/bootstrap/index.html @@ -16,7 +16,7 @@ - + @@ -94,6 +106,7 @@

First Grid

+
Date Of Birth + +
@@ -182,6 +195,18 @@

Second Grid

Date Of Birth + + + @@ -190,6 +215,7 @@

Second Grid

+ @@ -221,13 +247,13 @@

Second Grid

- - - - - + + + + + - + \ No newline at end of file diff --git a/demo/bootstrap/server-pagination.html b/demo/bootstrap/server-pagination.html index c3d5b73..50990cb 100644 --- a/demo/bootstrap/server-pagination.html +++ b/demo/bootstrap/server-pagination.html @@ -211,11 +211,11 @@

Angular Data Grid Server Pagination

- - - - - + + + + + diff --git a/demo/bootstrap/ui-router.html b/demo/bootstrap/ui-router.html new file mode 100644 index 0000000..20b37ed --- /dev/null +++ b/demo/bootstrap/ui-router.html @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + +
+
+

Angular Data Grid - UI Router Server Pagination.

+ UI Router plus all features for server pagination.
+ UI Router can be used in both modes (hash and html5). + Project GitHub +
+
+
+
+ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/bootstrap/views/anotherView.html b/demo/bootstrap/views/anotherView.html new file mode 100644 index 0000000..427c2e4 --- /dev/null +++ b/demo/bootstrap/views/anotherView.html @@ -0,0 +1,4 @@ +

Another View

+
+ +
\ No newline at end of file diff --git a/demo/bootstrap/views/router-server-pagination.html b/demo/bootstrap/views/router-server-pagination.html new file mode 100644 index 0000000..1d112af --- /dev/null +++ b/demo/bootstrap/views/router-server-pagination.html @@ -0,0 +1,169 @@ +
+
+ +
+
+
+
+
+ + +
+
+
+
+ + +
+ + + + +
+
+
+
+
+ + +
+ + + + +
+
+ +
+
+
+ + +
+
+
{{paginationOptions.totalItems}} items total
+
+
+
+
+
+
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + + +
Order # Date Placed + + Total
{{item.orderNo}}{{item.datePlaced | date:'MM/dd/yyyy'}}{{item.status}}{{item.total}}
+
+
{{paginationOptions.totalItems}} items total
+
+
+
+
+
+
+
+ + +
+
+
+
+
+
\ No newline at end of file diff --git a/demo/data.json b/demo/data.json index f2c15dc..edecf93 100644 --- a/demo/data.json +++ b/demo/data.json @@ -1,1157 +1,750 @@ -[{ - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 6100.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$6,100.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Valid", - "code": "3747453", - "placed": 1417402800000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1100.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,100.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747092", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1125.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,125.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747116", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1025.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,025.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747118", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1080.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,080.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747093", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1050.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,050.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747099", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1080.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,080.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747090", - "placed": 1397790000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1135.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,135.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747094", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 975.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$975.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747119", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 150.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$150.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747095", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 975.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$975.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747102", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1067.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,067.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747170", - "placed": 1400727600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1067.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,067.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747174", - "placed": 1401073200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 980.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$980.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747104", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1091.90, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,091.90" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747260", - "placed": 1404788400000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1067.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,067.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747171", - "placed": 1400727600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1100.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,100.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747086", - "placed": 1397790000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1092.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,092.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747173", - "placed": 1401073200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1125.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,125.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747084", - "placed": 1397790000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 975.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$975.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747106", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 950.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$950.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747122", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1025.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,025.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747100", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 75.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$75.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Complete", - "code": "3747070", - "placed": 1394766000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1122.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,122.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747164", - "placed": 1400727600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 975.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$975.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747107", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 50.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$50.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747083", - "placed": 1396580400000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 0.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$0.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747081", - "placed": 1395975600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1075.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,075.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747088", - "placed": 1397790000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1100.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,100.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747091", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1315.45, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,315.45" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747176", - "placed": 1401073200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1050.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,050.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747103", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1136.90, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,136.90" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747087", - "placed": 1397790000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1005.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,005.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747101", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1050.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,050.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747098", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 975.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$975.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747105", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1073.80, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,073.80" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747165", - "placed": 1400727600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1067.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,067.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747167", - "placed": 1400727600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1035.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,035.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747125", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 0.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$0.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747082", - "placed": 1395975600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1125.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,125.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747085", - "placed": 1397790000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1179.75, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,179.75" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747168", - "placed": 1400727600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1067.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,067.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747172", - "placed": 1401073200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 950.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$950.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747123", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 950.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$950.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747108", - "placed": 1398049200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1050.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,050.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747117", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1030.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,030.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747124", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1475.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,475.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747121", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 975.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$975.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747120", - "placed": 1398135600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1067.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,067.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747169", - "placed": 1400727600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1067.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,067.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747175", - "placed": 1401073200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1067.85, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,067.85" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747166", - "placed": 1400727600000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 5.95, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$5.95" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Complete", - "code": "3747349", - "placed": 1410145200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 59.50, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$59.50" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Complete", - "code": "3747352", - "placed": 1410145200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1125.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,125.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Complete", - "code": "3746995", - "placed": 1392260400000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 50.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$50.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Complete", - "code": "3746996", - "placed": 1392260400000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 0.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$0.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747016", - "placed": 1392606000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 61.90, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$61.90" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Valid", - "code": "3746998", - "placed": 1392260400000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 3125.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$3,125.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3746993", - "placed": 1391569200000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 130.95, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$130.95" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3746994", - "placed": 1392174000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 0.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$0.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747015", - "placed": 1392606000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 0.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$0.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747043", - "placed": 1392606000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 0.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$0.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Complete", - "code": "3747044", - "placed": 1392692400000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 0.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$0.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747014", - "placed": 1392606000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 20.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$20.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747017", - "placed": 1392606000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 50.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$50.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Complete", - "code": "3747045", - "placed": 1392692400000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 75.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$75.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Complete", - "code": "3747046", - "placed": 1392692400000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 50.00, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$50.00" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3747054", - "placed": 1393470000000 -}, { - "total": { - "currencyIso": "USD", - "priceType": "BUY", - "value": 1541.09, - "maxQuantity": null, - "minQuantity": null, - "formattedValue": "$1,541.09" - }, - "guid": null, - "managers": null, - "purchaseOrderNumber": null, - "status": null, - "b2bPermissionResults": null, - "statusDisplay": "Hold", - "code": "3746952", - "placed": 1384484400000 -}] \ No newline at end of file +[ + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 6100.00, + "formattedValue": "$6,100.00" + }, + "statusDisplay": "Valid", + "code": "3747453", + "placed": 1417402800000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1100.00, + "formattedValue": "$1,100.00" + }, + "statusDisplay": "Hold", + "code": "3747092", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1125.00, + "formattedValue": "$1,125.00" + }, + "statusDisplay": "Hold", + "code": "3747116", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1025.00, + "formattedValue": "$1,025.00" + }, + "statusDisplay": "Hold", + "code": "3747118", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1080.00, + "formattedValue": "$1,080.00" + }, + "statusDisplay": "Hold", + "code": "3747093", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1050.00, + "formattedValue": "$1,050.00" + }, + "statusDisplay": "Hold", + "code": "3747099", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1080.00, + "formattedValue": "$1,080.00" + }, + "statusDisplay": "Hold", + "code": "3747090", + "placed": 1397790000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1135.00, + "formattedValue": "$1,135.00" + }, + "statusDisplay": "Hold", + "code": "3747094", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 975.00, + "formattedValue": "$975.00" + }, + "statusDisplay": "Hold", + "code": "3747119", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 150.00, + "formattedValue": "$150.00" + }, + "statusDisplay": "Hold", + "code": "3747095", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 975.00, + "formattedValue": "$975.00" + }, + "statusDisplay": "Hold", + "code": "3747102", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1067.85, + "formattedValue": "$1,067.85" + }, + "statusDisplay": "Hold", + "code": "3747170", + "placed": 1400727600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1067.85, + "formattedValue": "$1,067.85" + }, + "statusDisplay": "Hold", + "code": "3747174", + "placed": 1401073200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 980.00, + "formattedValue": "$980.00" + }, + "statusDisplay": "Hold", + "code": "3747104", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1091.90, + "formattedValue": "$1,091.90" + }, + "statusDisplay": "Hold", + "code": "3747260", + "placed": 1404788400000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1067.85, + "formattedValue": "$1,067.85" + }, + "statusDisplay": "Hold", + "code": "3747171", + "placed": 1400727600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1100.00, + "formattedValue": "$1,100.00" + }, + "statusDisplay": "Hold", + "code": "3747086", + "placed": 1397790000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1092.85, + "formattedValue": "$1,092.85" + }, + "statusDisplay": "Hold", + "code": "3747173", + "placed": 1401073200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1125.00, + "formattedValue": "$1,125.00" + }, + "statusDisplay": "Hold", + "code": "3747084", + "placed": 1397790000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 975.00, + "formattedValue": "$975.00" + }, + "statusDisplay": "Hold", + "code": "3747106", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 950.00, + "formattedValue": "$950.00" + }, + "statusDisplay": "Hold", + "code": "3747122", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1025.00, + "formattedValue": "$1,025.00" + }, + "statusDisplay": "Hold", + "code": "3747100", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 75.00, + "formattedValue": "$75.00" + }, + "statusDisplay": "Complete", + "code": "3747070", + "placed": 1394766000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1122.85, + "formattedValue": "$1,122.85" + }, + "statusDisplay": "Hold", + "code": "3747164", + "placed": 1400727600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 975.00, + "formattedValue": "$975.00" + }, + "statusDisplay": "Hold", + "code": "3747107", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 50.00, + "formattedValue": "$50.00" + }, + "statusDisplay": "Hold", + "code": "3747083", + "placed": 1396580400000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 0.00, + "formattedValue": "$0.00" + }, + "statusDisplay": "Hold", + "code": "3747081", + "placed": 1395975600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1075.00, + "formattedValue": "$1,075.00" + }, + "statusDisplay": "Hold", + "code": "3747088", + "placed": 1397790000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1100.00, + "formattedValue": "$1,100.00" + }, + "statusDisplay": "Hold", + "code": "3747091", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1315.45, + "formattedValue": "$1,315.45" + }, + "statusDisplay": "Hold", + "code": "3747176", + "placed": 1401073200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1050.00, + "formattedValue": "$1,050.00" + }, + "statusDisplay": "Hold", + "code": "3747103", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1136.90, + "formattedValue": "$1,136.90" + }, + "statusDisplay": "Hold", + "code": "3747087", + "placed": 1397790000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1005.00, + "formattedValue": "$1,005.00" + }, + "statusDisplay": "Hold", + "code": "3747101", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1050.00, + "formattedValue": "$1,050.00" + }, + "statusDisplay": "Hold", + "code": "3747098", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 975.00, + "formattedValue": "$975.00" + }, + "statusDisplay": "Hold", + "code": "3747105", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1073.80, + "formattedValue": "$1,073.80" + }, + "statusDisplay": "Hold", + "code": "3747165", + "placed": 1400727600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1067.85, + "formattedValue": "$1,067.85" + }, + "statusDisplay": "Hold", + "code": "3747167", + "placed": 1400727600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1035.00, + "formattedValue": "$1,035.00" + }, + "statusDisplay": "Hold", + "code": "3747125", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 0.00, + "formattedValue": "$0.00" + }, + "statusDisplay": "Hold", + "code": "3747082", + "placed": 1395975600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1125.00, + "formattedValue": "$1,125.00" + }, + "statusDisplay": "Hold", + "code": "3747085", + "placed": 1397790000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1179.75, + "formattedValue": "$1,179.75" + }, + "statusDisplay": "Hold", + "code": "3747168", + "placed": 1400727600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1067.85, + "formattedValue": "$1,067.85" + }, + "statusDisplay": "Hold", + "code": "3747172", + "placed": 1401073200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 950.00, + "formattedValue": "$950.00" + }, + "statusDisplay": "Hold", + "code": "3747123", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 950.00, + "formattedValue": "$950.00" + }, + "statusDisplay": "Hold", + "code": "3747108", + "placed": 1398049200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1050.00, + "formattedValue": "$1,050.00" + }, + "statusDisplay": "Hold", + "code": "3747117", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1030.00, + "formattedValue": "$1,030.00" + }, + "statusDisplay": "Hold", + "code": "3747124", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1475.00, + "formattedValue": "$1,475.00" + }, + "statusDisplay": "Hold", + "code": "3747121", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 975.00, + "formattedValue": "$975.00" + }, + "statusDisplay": "Hold", + "code": "3747120", + "placed": 1398135600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1067.85, + "formattedValue": "$1,067.85" + }, + "statusDisplay": "Hold", + "code": "3747169", + "placed": 1400727600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1067.85, + "formattedValue": "$1,067.85" + }, + "statusDisplay": "Hold", + "code": "3747175", + "placed": 1401073200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1067.85, + "formattedValue": "$1,067.85" + }, + "statusDisplay": "Hold", + "code": "3747166", + "placed": 1400727600000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 5.95, + "formattedValue": "$5.95" + }, + "statusDisplay": "Complete", + "code": "3747349", + "placed": 1410145200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 59.50, + "formattedValue": "$59.50" + }, + "statusDisplay": "Complete", + "code": "3747352", + "placed": 1410145200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1125.00, + "formattedValue": "$1,125.00" + }, + "statusDisplay": "Complete", + "code": "3746995", + "placed": 1392260400000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 50.00, + "formattedValue": "$50.00" + }, + "statusDisplay": "Complete", + "code": "3746996", + "placed": 1392260400000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 0.00, + "formattedValue": "$0.00" + }, + "statusDisplay": "Hold", + "code": "3747016", + "placed": 1392606000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 61.90, + "formattedValue": "$61.90" + }, + "statusDisplay": "Valid", + "code": "3746998", + "placed": 1392260400000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 3125.00, + "formattedValue": "$3,125.00" + }, + "statusDisplay": "Hold", + "code": "3746993", + "placed": 1391569200000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 130.95, + "formattedValue": "$130.95" + }, + "statusDisplay": "Hold", + "code": "3746994", + "placed": 1392174000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 0.00, + "formattedValue": "$0.00" + }, + "statusDisplay": "Hold", + "code": "3747015", + "placed": 1392606000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 0.00, + "formattedValue": "$0.00" + }, + "statusDisplay": "Hold", + "code": "3747043", + "placed": 1392606000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 0.00, + "formattedValue": "$0.00" + }, + "statusDisplay": "Complete", + "code": "3747044", + "placed": 1392692400000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 0.00, + "formattedValue": "$0.00" + }, + "statusDisplay": "Hold", + "code": "3747014", + "placed": 1392606000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 20.00, + "formattedValue": "$20.00" + }, + "statusDisplay": "Hold", + "code": "3747017", + "placed": 1392606000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 50.00, + "formattedValue": "$50.00" + }, + "statusDisplay": "Complete", + "code": "3747045", + "placed": 1392692400000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 75.00, + "formattedValue": "$75.00" + }, + "statusDisplay": "Complete", + "code": "3747046", + "placed": 1392692400000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 50.00, + "formattedValue": "$50.00" + }, + "statusDisplay": "Hold", + "code": "3747054", + "placed": 1393470000000 + }, + { + "total": { + "currencyIso": "USD", + "priceType": "BUY", + "value": 1541.09, + "formattedValue": "$1,541.09" + }, + "statusDisplay": "Hold", + "code": "3746952", + "placed": 1384484400000 + } +] \ No newline at end of file diff --git a/demo/fixed-header/angular-md-grid.html b/demo/fixed-header/angular-md-grid.html new file mode 100644 index 0000000..78f4215 --- /dev/null +++ b/demo/fixed-header/angular-md-grid.html @@ -0,0 +1,259 @@ + + + + + Angular Data Grid - Fix Header Table + + + + + + + + + +
+ +
+ Angular Data Grid — Fix Header Table + + +
+
+ +
+
+
+

Fix Header Table

+ +

Features enabled: sorting, filtering, sync with browser URLs, pagination, item-per-page and fixed-header functionality. + Out-of-box Angular Material layout and + input controls used, + along with Material Design Light default CSS for + grid styling. + Project GitHub

+ +
+

How To Freeze Table Header

+

Using HTML Layout

+
+

The first option is to split table header and table body in two tables. + One way to do this is to follow the next steps:

+
    +
  • Use the next styles (with any fixed height) applied to table body container to make it scrollable:
    + .div-table-body { height: 600px; overflow-x: auto; overflow-y: scroll; }
    +
  • +
  • Make sure that th elements have the same padding as td elements have.
  • +
  • Use padding-right with the value of scroll bar width to make an offset for the table contains header.
  • +
  • Use width attribute for columns to sync widths.
  • +
+

Code Sample: +

+<table>
+    <thead>
+        ...
+    </thead>
+</table>
+<table>
+    <tbody class="div-table-body">
+        ...
+    </tbody>
+</table>
+        
+

+
+

Using Stand-alone Directive

+
+

Another option is to use the directive fixed-header that can be injected to the Data Grid like a separate module dataGridUtils.

+

To make it work it is needed to perform next steps:

+
    +
  • Include script to your application:
    + <script src="bower_components/angular-data-grid/dist/dataGridUtils.min.js"></script> +
  • +
  • Include css stylesheets to your application:
    + <link rel="stylesheet" href="bower_components/angular-data-grid/css/fixedHeader/fixed-header.css"> +
  • +
  • Inject dataGridUtils dependency in your module:
    + angular.module('myApp', ['dataGrid', 'dataGridUtils.fixedHeader']) +
  • +
  • Apply the directive fixed-header to the grid table:
    + <table class="table" fixed-header> +
  • +
+

The directive uses z-index: 99 if your page uses the same value or higher please make appropriate changes to fixed-header.scss file.

+

The directive also has additional attribute offset-from-element. + It is needed if you already have some other elements with fixed position above the table. + In this case you need to pass a class or id of the very last element (if there are several) to this attribute + to make the directive take + into consideration that header needs to be fixed with offset from above elements.

+

Example:
+

<table class="table" fixed-header offset-from-element=".the-class-on-above-fixed-element">
+ or +
<table class="table" fixed-header offset-from-element="#the-id-on-above-fixed-element”>
+

+
+

The directive subscribes on scroll event, but the event is not fired when directive is used inside <md-content>, so to make it work please use the directive + outside the <md-content> container. + For more information about this problem please review this issue. +

+
+
+
+
+
+ + + +
+
+ + +
+
+ + +
+
+ Clear Dates + +
+
+
+
+
+ {{filtered.length}} items total +
+
+
+ + + + 10 + 25 + 50 + 75 + + +
+
+
+
+ + + + + + + + + + + + + + + + + +
+ Order # + + + + All Statuses + + {{option.text}} + + + + Date Placed + + + Total + +
+ +
+
+
+ + + + 10 + 25 + 50 + 75 + + +
+
+
+ CodePen +
+

See the Pen eJWWpM by AngularDataGrid (@AngularDataGrid) on CodePen. +

+ +
+
+
+
+
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/fixed-header/bootstrap-grid.html b/demo/fixed-header/bootstrap-grid.html new file mode 100644 index 0000000..b1e7991 --- /dev/null +++ b/demo/fixed-header/bootstrap-grid.html @@ -0,0 +1,279 @@ + + + + + Angular Data Grid - Fix Header Table + + + + + + + + + +
+
+

Fix Header Table

+ Features enabled: sorting, filtering (using both in-grid and external controls), sync with browser URLs, pagination, items-per-page and fixed-header functionality. + Angular UI Datepicker used for date controls, although you can use any other framework, plugin or styling. + Project GitHub +
+
+

How To Freeze Table Header

+

Using HTML Layout

+
+

The first option is to split table header and table body in two tables. + One way to do this is to follow the next steps:

+ +

Code Sample: +

+<table>
+    <thead>
+        ...
+    </thead>
+</table>
+<table>
+    <tbody class="div-table-body">
+        ...
+    </tbody>
+</table>
+        
+

+
+

Using Stand-alone Directive

+
+

Another option is to use the directive fixed-header that can be injected to the Data Grid like a separate module dataGridUtils.

+

To make it work it is needed to perform next steps:

+ +

The directive uses z-index: 99 if your page uses the same value or higher please make appropriate changes to fixed-header.scss file.

+

The directive also has additional attribute offset-from-element. + It is needed if you already have some other elements with fixed position above the table. + In this case you need to pass a class or id of the very last element (if there are several) to this attribute + to make the directive take + into consideration that header needs to be fixed with offset from above elements.

+

Example:
+

<table class="table" fixed-header offset-from-element=".the-class-on-above-fixed-element">
+ or +
<table class="table" fixed-header offset-from-element="#the-id-on-above-fixed-element">
+

+
+
+
+
+
+
+ + +
+
+
+
+ + +
+ + + + +
+
+
+
+
+ + +
+ + + + +
+
+ +
+
+
+
+
+
+
+
+
+ {{filtered.length}} items total +
+
+
+
+ +
+
+ + +
+
+
+
+ + + + + + + + + + + + + + + + + +
+ Order # + + Date Placed + + + + Total +
+
+
+ +
+
+ + +
+
+
+
+
+
+
+ +
+

See the Pen xZddZm by AngularDataGrid (@AngularDataGrid) on CodePen.

+ +
+
+
+
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/demo/fixed-header/css/fixed-header.bootstrap.css b/demo/fixed-header/css/fixed-header.bootstrap.css new file mode 100644 index 0000000..421dc34 --- /dev/null +++ b/demo/fixed-header/css/fixed-header.bootstrap.css @@ -0,0 +1,16 @@ +.fixed-header { + border: none; } + .fixed-header tr { + background-color: #fff; } + +.tbody-offset:before { + color: white; + height: 60px; } + +.fixed-nav { + position: fixed; + width: 100%; + z-index: 5; } + +.padding-top-50 { + padding-top: 50px; } diff --git a/demo/fixed-header/css/fixed-header.material.css b/demo/fixed-header/css/fixed-header.material.css new file mode 100644 index 0000000..d1ce846 --- /dev/null +++ b/demo/fixed-header/css/fixed-header.material.css @@ -0,0 +1,8 @@ +.fixed-header { + border: 1px solid rgba(0, 0, 0, 0.12); } + .fixed-header tr { + background-color: #fff; } + +.tbody-offset:before { + color: white; + height: 60px; } diff --git a/demo/fixed-header/js/bootstrap/demoApp.js b/demo/fixed-header/js/bootstrap/demoApp.js new file mode 100644 index 0000000..8ec93b1 --- /dev/null +++ b/demo/fixed-header/js/bootstrap/demoApp.js @@ -0,0 +1,28 @@ +angular.module('myApp', ['ui.bootstrap', 'dataGrid', 'pagination', 'dataGridUtils.fixedHeader']) + .controller('myAppController', ['$scope', 'myAppFactory', function ($scope, myAppFactory) { + + $scope.gridOptions = { + data: [], + urlSync: true, + pagination: { + itemsPerPage: '75', + currentPage: 1 + } + }; + + myAppFactory.getData().then(function (responseData) { + $scope.gridOptions.data = responseData.data; + }); + + }]) + .factory('myAppFactory', function ($http) { + return { + getData: function () { + return $http({ + method: 'GET', + url: 'https://angular-data-grid.github.io/demo/data.json' + }); + } + } + }); + diff --git a/demo/fixed-header/js/material-design/demoApp.js b/demo/fixed-header/js/material-design/demoApp.js new file mode 100644 index 0000000..0532f3d --- /dev/null +++ b/demo/fixed-header/js/material-design/demoApp.js @@ -0,0 +1,27 @@ +angular.module('myApp', ['dataGrid', 'pagination', 'ngMaterial', 'dataGridUtils.fixedHeader']) + .controller('myAppController', ['$scope', 'myAppFactory', function ($scope, myAppFactory) { + + $scope.gridOptions = { + data: [], + urlSync: true, + pagination: { + itemsPerPage: '75', + currentPage: 1 + } + }; + myAppFactory.getData().then(function (responseData) { + $scope.gridOptions.data = responseData.data; + }); + + }]) + .factory('myAppFactory', function ($http) { + return { + getData: function () { + return $http({ + method: 'GET', + url: 'https://angular-data-grid.github.io/demo/data.json' + }); + } + } + }); + diff --git a/demo/fixed-header/scss/fixed-header.bootstrap.scss b/demo/fixed-header/scss/fixed-header.bootstrap.scss new file mode 100644 index 0000000..8c6ff62 --- /dev/null +++ b/demo/fixed-header/scss/fixed-header.bootstrap.scss @@ -0,0 +1,25 @@ +//styles specific to bootstrap sample (not required) +.fixed-header { + border: none; + tr { + background-color: #fff; + } +} + +.tbody-offset { + &:before { + color: white; + height: 60px; + } +} + +.fixed-nav { + position: fixed; + width: 100%; + z-index: 5; +} + +.padding-top-50 { + padding-top: 50px; +} + diff --git a/demo/fixed-header/scss/fixed-header.material.scss b/demo/fixed-header/scss/fixed-header.material.scss new file mode 100644 index 0000000..b1dfee6 --- /dev/null +++ b/demo/fixed-header/scss/fixed-header.material.scss @@ -0,0 +1,14 @@ +//styles specific to material design sample (not required) +.fixed-header { + border: 1px solid rgba(0,0,0,.12); + tr { + background-color: #fff; + } +} + +.tbody-offset { + &:before { + color: white; + height: 60px; + } +} \ No newline at end of file diff --git a/demo/material/css/angular-data-grid.material.css b/demo/material/css/angular-data-grid.material.css index 7e6dc66..7edbd95 100644 --- a/demo/material/css/angular-data-grid.material.css +++ b/demo/material/css/angular-data-grid.material.css @@ -51,33 +51,19 @@ th md-select { .pagination-page.active a { color: #fff; } -.material-icons, .sortable span:before, .sortable span:after { - font-family: 'Material Icons'; - font-size: 18px; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; } +.sortable .arrow { + position: relative; + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; } -.sortable span { - position: relative; } - .sortable span:before { - content: 'arrow_drop_down'; - position: absolute; - right: -18px; - top: -2px; } - .sortable span:after { - content: 'arrow_drop_up'; - position: absolute; - right: -18px; - top: -9px; } +.sortable.sort-ascent .arrow { + top: -10px; + left: 5px; + border-bottom: 4px solid #757575; } -.sortable.sort-ascent span:before { - display: none; } - -.sortable.sort-ascent span:after { - top: -5px; } - -.sortable.sort-descent span:before { - top: -5px; } - -.sortable.sort-descent span:after { - display: none; } +.sortable.sort-descent .arrow { + top: 10px; + left: 5px; + border-top: 4px solid #757575; } diff --git a/demo/material/index.html b/demo/material/index.html index da5b4a1..76acecd 100644 --- a/demo/material/index.html +++ b/demo/material/index.html @@ -5,8 +5,8 @@ Angular Data Grid - Material Design - - + + @@ -14,7 +14,6 @@
Angular Data Grid — Material Design - @@ -33,21 +32,26 @@
- +
-
-

Angular Data Grid sample using Material Design styling

+

Angular Data Grid sample using Material Design styling

-

Features enabled: sorting, filtering, sync with browser URLs, pagination and item-per-page functionality. - Out-of-box Angular Material layout and input controls used, - along with Material Design Light default CSS for grid styling. - Project GitHub

-
+

Features enabled: sorting, filtering, sync with browser URLs, pagination and item-per-page functionality. + Out-of-box Angular Material layout and input controls used, + along with Material Design Light default CSS for grid styling. + Project GitHub

+

Additional Demos

+
+
-
- +
+ Angular Data Grid sample using Material Design styling aria-invalid="false">
-
+
+ ng-change="gridActions.filter()"> +
-
+
+ ng-change="gridActions.filter()"> +
-
- Clear Dates +
+ Clear Dates +
@@ -99,10 +106,10 @@

Angular Data Grid sample using Material Design styling

items-per-page="paginationOptions.itemsPerPage"> - 10 - 25 - 50 - 75 + 10 + 25 + 50 + 75
@@ -114,6 +121,7 @@

Angular Data Grid sample using Material Design styling

Order # + Angular Data Grid sample using Material Design styling Date Placed + Total + @@ -159,10 +169,10 @@

Angular Data Grid sample using Material Design styling

items-per-page="paginationOptions.itemsPerPage"> - 10 - 25 - 50 - 75 + 10 + 25 + 50 + 75
@@ -177,15 +187,15 @@

Angular Data Grid sample using Material Design styling


- +
- - - - - + + + + + diff --git a/demo/material/scss/angular-data-grid.material.scss b/demo/material/scss/angular-data-grid.material.scss index ff688a7..fdb8d81 100644 --- a/demo/material/scss/angular-data-grid.material.scss +++ b/demo/material/scss/angular-data-grid.material.scss @@ -64,44 +64,26 @@ th md-select { } } } -.material-icons { - font-family: 'Material Icons'; - font-size: 18px; - -webkit-font-feature-settings: 'liga'; - -webkit-font-smoothing: antialiased; -} .sortable { - span { + .arrow { position: relative; - &:before { - @extend .material-icons; - content: 'arrow_drop_down'; - position: absolute; - right: -18px; - top: -2px; - } - &:after { - @extend .material-icons; - content: 'arrow_drop_up'; - position: absolute; - right: -18px; - top: -9px; - } + width: 0; + height: 0; + border-left: 4px solid transparent; + border-right: 4px solid transparent; } &.sort-ascent { - span:before { - display: none; - } - span:after { - top: -5px + .arrow { + top: -10px; + left: 5px; + border-bottom: 4px solid $backgroundArrows; } } &.sort-descent { - span:before { - top: -5px - } - span:after { - display: none; + .arrow { + top: 10px; + left: 5px; + border-top: 4px solid $backgroundArrows; } } } \ No newline at end of file diff --git a/demo/material/scss/angular-data-grid.variables.scss b/demo/material/scss/angular-data-grid.variables.scss index 60b1dda..2c7053a 100644 --- a/demo/material/scss/angular-data-grid.variables.scss +++ b/demo/material/scss/angular-data-grid.variables.scss @@ -2,4 +2,5 @@ $backgroundActive: rgb(63, 81, 181); $foregroundActive: #fff; $foregroundPagination: #ddd; $foregroundDefault: #444; -$backgroundIcons: #333; \ No newline at end of file +$backgroundIcons: #333; +$backgroundArrows: #757575; \ No newline at end of file diff --git a/dist/JSONToCSVConvertor.js b/dist/JSONToCSVConvertor.js new file mode 100644 index 0000000..3fce1b6 --- /dev/null +++ b/dist/JSONToCSVConvertor.js @@ -0,0 +1,84 @@ +function JSONToCSVConvertor(JSONData, ReportTitle, ShowLabel) { + //If JSONData is not an object then JSON.parse will parse the JSON string in an Object + var arrData = typeof JSONData != 'object' ? JSON.parse(JSONData) : JSONData; + + var CSV = ''; + //Set Report title in first row or line + + CSV += ReportTitle + '\r\n\n'; + + var currentDate = new Date(); + + CSV += currentDate + '\r\n\n'; + + //This condition will generate the Label/Header + if (ShowLabel) { + var row = ""; + + //This loop will extract the label from 1st index of on array + for (var index in arrData[0]) { + + //Now convert each value to string and comma-seprated + row += index + ','; + } + + row = row.slice(0, -1); + + //append Label row with line break + CSV += row + '\r\n'; + } + + //1st loop is to extract each row + for (var i = 0; i < arrData.length; i++) { + var row = ""; + + //2nd loop will extract each column and convert it in string comma-seprated + for (var index in arrData[i]) { + row += '"' + arrData[i][index] + '",'; + } + + row.slice(0, row.length - 1); + + //add a line break after each row + CSV += row + '\r\n'; + } + + if (CSV == '') { + alert("Invalid data"); + return; + } + + //Generate a file name + var fileName = ""; + //this will remove the blank-spaces from the title and replace it with an underscore + fileName += ReportTitle.replace(/ /g, "_"); + + //Initialize file format you want csv or xls + var uri = 'data:text/csv;charset=utf-8,' + escape(CSV); + + // Now the little tricky part. + // you can use either>> window.open(uri); + // but this will not work in some browsers + // or you will not get the correct file extension + + //this trick will generate a temp tag + + if (navigator.msSaveBlob) { + uri = 'data:text/csv;charset=utf-8,' + CSV; + navigator.msSaveBlob(new Blob([uri], {type: 'text/csv;charset=utf-8;'}), fileName + ".csv"); + } + + else { + var link = document.createElement("a"); + link.href = uri; + + //set the visibility hidden so it will not effect on your web-layout + link.style = "visibility:hidden"; + link.download = fileName + ".csv"; + + //this part will append the anchor tag and remove it after automatic click + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } +} \ No newline at end of file diff --git a/dist/css/fixedHeader/fixed-header.css b/dist/css/fixedHeader/fixed-header.css new file mode 100644 index 0000000..29c52fc --- /dev/null +++ b/dist/css/fixedHeader/fixed-header.css @@ -0,0 +1,10 @@ +.fixed-header { + top: 0; + position: fixed; + width: auto; + display: table; + z-index: 99; } + +.tbody-offset:before { + content: " "; + display: block; } diff --git a/dist/dataGrid.js b/dist/dataGrid.js index 8917d18..d7ddb3f 100644 --- a/dist/dataGrid.js +++ b/dist/dataGrid.js @@ -12,7 +12,7 @@ return []; } }) - .controller('gridController', ['$scope', '$element', '$filter', '$location', 'filtersFactory', function ($scope, $element, $filter, $location, filtersFactory) { + .controller('gridController', ['$scope', '$rootScope', '$element', '$filter', '$location', 'filtersFactory', function ($scope, $rootScope, $element, $filter, $location, filtersFactory) { // values by default $scope._gridOptions = $scope.$eval($element.attr('grid-options')); $scope._gridActions = $scope.$eval($element.attr('grid-actions')); @@ -29,7 +29,7 @@ $scope.filtered = $scope._gridOptions.data.slice(); $scope.paginationOptions = $scope._gridOptions.pagination ? angular.copy($scope._gridOptions.pagination) : {}; $scope.defaultsPaginationOptions = { - itemsPerPage: $scope.paginationOptions.itemsPerPage || '10', + itemsPerPage: $scope.paginationOptions.itemsPerPage, currentPage: $scope.paginationOptions.currentPage || 1 }; $scope.paginationOptions = angular.copy($scope.defaultsPaginationOptions); @@ -37,8 +37,8 @@ $scope.customFilters = $scope._gridOptions.customFilters ? angular.copy($scope._gridOptions.customFilters) : {}; $scope.urlSync = $scope._gridOptions.urlSync; - $scope.$watch('_gridOptions.data', function (newValue) { - if (newValue && newValue.length) { + $scope.$watchCollection('_gridOptions.data', function (newValue) { + if (newValue && newValue.length > -1) { $scope.sortCache = {}; $scope.filtered = $scope._gridOptions.data.slice(); $scope.filters.forEach(function (filter) { @@ -48,7 +48,7 @@ }); if ($scope.urlSync) { - parseUrl($location.path()); + parseUrl(); } else { applyFilters(); } @@ -71,15 +71,11 @@ }; $scope.$on('$locationChangeSuccess', function () { - if ($scope.urlSync || $scope.serverPagination) { - if ($scope.serverPagination) { - clearTimeout($scope.getDataTimeout); - $scope.getDataTimeout = setTimeout(getData, $scope.getDataDelay); - } - if ($scope.filtered) { - parseUrl($location.path()); - } - } + onChangeStateOrLocation() + }); + + $scope.$on("$stateChangeSuccess", function (event, toState) { + onChangeStateOrLocation() }); $scope.reloadGrid = function (isDefaultSort) { @@ -88,12 +84,25 @@ } else { applyFilters(); } + $rootScope.$broadcast('gridReloaded'); }; $scope._gridActions.refresh = $scope.reloadGrid; $scope._gridActions.filter = $scope.filter; $scope._gridActions.sort = $scope.sort; + function onChangeStateOrLocation(){ + if ($scope.urlSync || $scope.serverPagination) { + if ($scope.serverPagination) { + clearTimeout($scope.getDataTimeout); + $scope.getDataTimeout = setTimeout(getData, $scope.getDataDelay); + } + if ($scope.filtered) { + parseUrl(); + } + } + } + function changePath(isDefaultSort) { var path, needApplyFilters = false; @@ -134,27 +143,21 @@ if (needApplyFilters) { applyFilters(); } - $location.path(path); + $location.search(path); if (isDefaultSort) { $scope.$apply(); } } function parseUrl() { - var url = $location.path().slice(1), - params = {}, + var params = $location.search(), customParams = {}; - $scope.params = params; - - url.split('&').forEach(function (urlParam) { - var param = urlParam.split('='); - params[param[0]] = param[1]; - if (param[0] !== 'page' && param[0] !== 'sort' && param[0] !== 'itemsPerPage') { - customParams[decodeURIComponent(param[0])] = decodeURIComponent(param[1]); - } + Object.keys(params).forEach(function(key) { + if (key !== 'page' && key !== 'sort' && key !== 'itemsPerPage') { + customParams[key] = params[key]; } - ); + }); //custom filters $scope.filters.forEach(function (filter) { @@ -216,7 +219,12 @@ } function getData() { - var url = $location.path().slice(1); + var url = ''; + var params = $location.search(); + Object.keys(params).forEach(function(key) { + url += key + '=' + params[key] + '&'; + }); + url = url.slice(0, -1); if (!url && $scope.sortOptions.predicate) { $scope.sort($scope.sortOptions.predicate, true); } else { @@ -282,6 +290,23 @@ }); } }]) + .directive('gridItem', ['$compile', function ($compile) { + return { + restrict: 'EA', + terminal:true, + scope: false, + link: function ($scope, element, attrs, ctrl, transclude) { + if ($scope.serverPagination) { + element.attr('ng-repeat', "item in filtered"); + } else { + element.attr('ng-repeat', "item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage track by $index"); + } + element.removeAttr('grid-item'); + var html = element[0].outerHTML; + element.replaceWith($compile(html)($scope)); + } + } + }]) .directive('gridData', ['$compile', '$animate', function ($compile) { return { restrict: 'EA', @@ -290,29 +315,27 @@ scope: true, controller: 'gridController', link: function ($scope, $element, attrs) { - var sorting = [], - filters = [], - rows = [], + var filters = [], directiveElement = $element.parent(), gridId = attrs.id, serverPagination = attrs.serverPagination === 'true'; + $scope.serverPagination = serverPagination; angular.forEach(angular.element(directiveElement[0].querySelectorAll('[sortable]')), function (sortable) { var element = angular.element(sortable), predicate = element.attr('sortable'); - sorting.push(element); element.attr('ng-class', "{'sort-ascent' : sortOptions.predicate ==='" + predicate + "' && sortOptions.direction === 'asc', 'sort-descent' : sortOptions.predicate === '" + predicate + "' && sortOptions.direction === 'desc'}"); element.attr('ng-click', "sort('" + predicate + "')"); $compile(element)($scope); }); - - angular.forEach(angular.element(document.querySelectorAll('[filter-by]')), function (filter) { + angular.forEach(document.querySelectorAll('[filter-by]'), function (filter) { var element = angular.element(filter), - isInScope = $element.find(element).length > 0, predicate = element.attr('filter-by'), + dataGridElement = document.querySelectorAll('[grid-data]')[0], + isInScope = dataGridElement.querySelectorAll('[filter-by="'+ predicate+'"]').length > 0, filterType = element.attr('filter-type') || '', urlName = element.attr('ng-model'), disableUrl = element.attr('disable-url'); @@ -348,19 +371,6 @@ }); }); - angular.forEach(angular.element(directiveElement[0].querySelectorAll('[grid-item]')), function (row) { - var element = angular.element(row); - rows.push(element); - if (serverPagination) { - element.attr('ng-repeat', "item in filtered"); - } else { - element.attr('ng-repeat', "item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage track by $index"); - } - $compile(element)($scope); - }); - - $scope.sorting = sorting; - $scope.rows = rows; $scope.filters = filters; } } diff --git a/dist/dataGrid.min.js b/dist/dataGrid.min.js index 82ad512..a3a012d 100644 --- a/dist/dataGrid.min.js +++ b/dist/dataGrid.min.js @@ -1 +1 @@ -!function(){"use strict";function t(t,e){var i=[];return t?(t.forEach(function(t){~i.indexOf(t[e])||i.push(t[e])}),i.map(function(t){return{text:t,value:t}})):void 0}angular.module("dataGrid",[]).filter("startFrom",function(){return function(t,e){return t?(e=+e,t.slice(e)):[]}}).controller("gridController",["$scope","$element","$filter","$location","filtersFactory",function(e,i,r,n,a){function o(t){var i,r=!1;i="page="+e.paginationOptions.currentPage,e.paginationOptions.itemsPerPage!==e.defaultsPaginationOptions.itemsPerPage&&(i+="&itemsPerPage="+e.paginationOptions.itemsPerPage),e.sortOptions.predicate&&(i+="&sort="+encodeURIComponent(e.sortOptions.predicate+"-"+e.sortOptions.direction)),e.filters.forEach(function(t){var n=t.model,a=t.isInScope?e.$eval(n):e.$parent.$eval(n);if(t.disableUrl)return void(r=!0);if(a){var o;if(a instanceof Date){if(isNaN(a.getTime()))return;o=a.getFullYear()+"-",o+=a.getMonth()<9?"0"+(a.getMonth()+1)+"-":a.getMonth()+1+"-",o+=a.getDate()<10?"0"+a.getDate():a.getDate(),a=o}i+="&"+encodeURIComponent(n)+"="+encodeURIComponent(a)}}),r&&c(),n.path(i),t&&e.$apply()}function s(){var t=n.path().slice(1),i={},r={};if(e.params=i,t.split("&").forEach(function(t){var e=t.split("=");i[e[0]]=e[1],"page"!==e[0]&&"sort"!==e[0]&&"itemsPerPage"!==e[0]&&(r[decodeURIComponent(e[0])]=decodeURIComponent(e[1]))}),e.filters.forEach(function(t){var i=t.model,n=r[i];if(!t.disableUrl){if(~t.filterType.toLowerCase().indexOf("date"))return e.$parent.__evaltmp=n?new Date(n):null,void e.$parent.$eval(i+"=__evaltmp");"select"!==t.filterType||n||(n=""),n&&(t.isInScope?(e.__evaltmp=n,e.$eval(i+"=__evaltmp")):(e.$parent.__evaltmp=n,e.$parent.$eval(i+"=__evaltmp")))}}),e.paginationOptions.itemsPerPage=e.defaultsPaginationOptions.itemsPerPage,e.paginationOptions.currentPage=e.defaultsPaginationOptions.currentPage,i.itemsPerPage&&(e.paginationOptions.itemsPerPage=i.itemsPerPage),i.page&&(!e.serverPagination&&(i.page-1)*e.paginationOptions.itemsPerPage>e.filtered.length?e.paginationOptions.currentPage=1:e.paginationOptions.currentPage=i.page),i.sort){var a=i.sort.split("-");e.sortOptions.predicate=decodeURIComponent(a[0]),e.sortOptions.direction=decodeURIComponent(a[1])}e.serverPagination||c()}function l(){var t=n.path().slice(1);!t&&e.sortOptions.predicate?e.sort(e.sortOptions.predicate,!0):e._gridOptions.getData("?"+t,function(t,i){e.filtered=t,e.paginationOptions.totalItems=i})}function c(){var t=Date.now(),i=!1;e._time={},e.sortOptions.predicate&&e.sortCache&&e.sortCache.predicate===e.sortOptions.predicate&&e.sortCache.direction===e.sortOptions.direction?(e.filtered=e.sortCache.data.slice(),i=!0):e.filtered=e._gridOptions.data.slice(),e._time.copy=Date.now()-t;var n=Date.now();p(),e._time.filters=Date.now()-n;var a=Date.now();e.sortOptions.predicate&&!i&&(e.filtered=r("orderBy")(e.filtered,e.sortOptions.predicate,"desc"===e.sortOptions.direction),e.sortCache={data:e.filtered.slice(),predicate:e.sortOptions.predicate,direction:e.sortOptions.direction}),e._time.sort=Date.now()-a,e._time.all=Date.now()-t,e.paginationOptions.totalItems=e.filtered.length}function p(){e.filters.forEach(function(t){var i=t.filterBy,r=t.model,n=t.isInScope?e.$eval(r):e.$parent.$eval(r),o=t.filterType;if(e.customFilters[r])e.filtered=e.customFilters[r](e.filtered,n,i);else if(n&&o){var s=a.getFilterByType(o);s&&(e.filtered=s(e.filtered,n,i))}})}e._gridOptions=e.$eval(i.attr("grid-options")),e._gridActions=e.$eval(i.attr("grid-actions")),e.serverPagination="true"===i.attr("server-pagination"),e.getDataDelay=i.attr("get-delay")||350,e._gridActions||(e.$parent.$eval(i.attr("grid-actions")+"= {}"),e._gridActions=e.$parent.$eval(i.attr("grid-actions"))),e._gridOptions.grid=e,e.filtered=e._gridOptions.data.slice(),e.paginationOptions=e._gridOptions.pagination?angular.copy(e._gridOptions.pagination):{},e.defaultsPaginationOptions={itemsPerPage:e.paginationOptions.itemsPerPage||"10",currentPage:e.paginationOptions.currentPage||1},e.paginationOptions=angular.copy(e.defaultsPaginationOptions),e.sortOptions=e._gridOptions.sort?angular.copy(e._gridOptions.sort):{},e.customFilters=e._gridOptions.customFilters?angular.copy(e._gridOptions.customFilters):{},e.urlSync=e._gridOptions.urlSync,e.$watch("_gridOptions.data",function(i){i&&i.length&&(e.sortCache={},e.filtered=e._gridOptions.data.slice(),e.filters.forEach(function(i){"select"===i.filterType&&(e[i.model+"Options"]=t(e.filtered,i.filterBy))}),e.urlSync?s(n.path()):c())}),e.sort=function(t,i){if(!i){var r=e.sortOptions.predicate===t&&"desc"===e.sortOptions.direction?"asc":"desc";e.sortOptions.direction=r,e.sortOptions.predicate=t}e.paginationOptions.currentPage=1,e.reloadGrid(i)},e.filter=function(){e.paginationOptions.currentPage=1,e.reloadGrid()},e.$on("$locationChangeSuccess",function(){(e.urlSync||e.serverPagination)&&(e.serverPagination&&(clearTimeout(e.getDataTimeout),e.getDataTimeout=setTimeout(l,e.getDataDelay)),e.filtered&&s(n.path()))}),e.reloadGrid=function(t){e.urlSync||e.serverPagination?o(t):c()},e._gridActions.refresh=e.reloadGrid,e._gridActions.filter=e.filter,e._gridActions.sort=e.sort}]).directive("gridData",["$compile","$animate",function(e){return{restrict:"EA",scope:!0,controller:"gridController",link:function(i,r,n){var a=[],o=[],s=[],l=r.parent(),c=n.id,p="true"===n.serverPagination;angular.forEach(angular.element(l[0].querySelectorAll("[sortable]")),function(t){var r=angular.element(t),n=r.attr("sortable");a.push(r),r.attr("ng-class","{'sort-ascent' : sortOptions.predicate ==='"+n+"' && sortOptions.direction === 'asc', 'sort-descent' : sortOptions.predicate === '"+n+"' && sortOptions.direction === 'desc'}"),r.attr("ng-click","sort('"+n+"')"),e(r)(i)}),angular.forEach(angular.element(document.querySelectorAll("[filter-by]")),function(e){var n=angular.element(e),a=r.find(n).length>0,s=n.attr("filter-by"),l=n.attr("filter-type")||"",p=n.attr("ng-model"),d=n.attr("disable-url");c&&n.attr("grid-id")&&c!=n.attr("grid-id")||("select"!==l||(i[p+"Options"]=t(i.$eval(r.attr("grid-options")+".data"),s)),!~l.indexOf("date")||n.attr("ng-focus")||n.attr("ng-blur")||(n.attr("ng-focus","filter('{"+p+" : this."+p+"}')"),n.attr("ng-blur","filter('{"+p+" : this."+p+"}')")),p||(p=s,n.attr("ng-model",s),n.attr("ng-change","filter()")),o.push({model:p,isInScope:a,filterBy:s,filterType:l,disableUrl:d}))}),angular.forEach(angular.element(l[0].querySelectorAll("[grid-item]")),function(t){var r=angular.element(t);s.push(r),p?r.attr("ng-repeat","item in filtered"):r.attr("ng-repeat","item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage track by $index"),e(r)(i)}),i.sorting=a,i.rows=s,i.filters=o}}}]).factory("filtersFactory",function(){function t(t,e,i){return t.filter(function(t){return e&&t[i]?t[i]===e:!0})}function e(t,e,i){return t.filter(function(t){return e&&t[i]?~(t[i]+"").toLowerCase().indexOf((e+"").toLowerCase()):!!t[i]})}function i(t,e,i){return e=new Date(e).getTime(),t.filter(function(t){return e&&t[i]?t[i]<=e+86399999:!0})}function r(t,e,i){return e=new Date(e).getTime(),t.filter(function(t){return e&&t[i]?t[i]>=e:!0})}return{getFilterByType:function(n){switch(n){case"select":return t;case"text":return e;case"dateTo":return i;case"dateFrom":return r;default:return null}}}})}(); \ No newline at end of file +!function(){"use strict";function t(t,e){var i=[];if(t)return t.forEach(function(t){~i.indexOf(t[e])||i.push(t[e])}),i.map(function(t){return{text:t,value:t}})}angular.module("dataGrid",[]).filter("startFrom",function(){return function(t,e){return t?(e=+e,t.slice(e)):[]}}).controller("gridController",["$scope","$rootScope","$element","$filter","$location","filtersFactory",function(e,i,r,n,a,o){function s(){(e.urlSync||e.serverPagination)&&(e.serverPagination&&(clearTimeout(e.getDataTimeout),e.getDataTimeout=setTimeout(p,e.getDataDelay)),e.filtered&&l())}function c(t){var i,r=!1;i="page="+e.paginationOptions.currentPage,e.paginationOptions.itemsPerPage!==e.defaultsPaginationOptions.itemsPerPage&&(i+="&itemsPerPage="+e.paginationOptions.itemsPerPage),e.sortOptions.predicate&&(i+="&sort="+encodeURIComponent(e.sortOptions.predicate+"-"+e.sortOptions.direction)),e.filters.forEach(function(t){var n=t.model,a=t.isInScope?e.$eval(n):e.$parent.$eval(n);if(t.disableUrl)return void(r=!0);if(a){var o;if(a instanceof Date){if(isNaN(a.getTime()))return;o=a.getFullYear()+"-",o+=a.getMonth()<9?"0"+(a.getMonth()+1)+"-":a.getMonth()+1+"-",o+=a.getDate()<10?"0"+a.getDate():a.getDate(),a=o}i+="&"+encodeURIComponent(n)+"="+encodeURIComponent(a)}}),r&&d(),a.search(i),t&&e.$apply()}function l(){var t=a.search(),i={};if(Object.keys(t).forEach(function(e){"page"!==e&&"sort"!==e&&"itemsPerPage"!==e&&(i[e]=t[e])}),e.filters.forEach(function(t){var r=t.model,n=i[r];if(!t.disableUrl){if(~t.filterType.toLowerCase().indexOf("date"))return e.$parent.__evaltmp=n?new Date(n):null,void e.$parent.$eval(r+"=__evaltmp");"select"!==t.filterType||n||(n=""),n&&(t.isInScope?(e.__evaltmp=n,e.$eval(r+"=__evaltmp")):(e.$parent.__evaltmp=n,e.$parent.$eval(r+"=__evaltmp")))}}),e.paginationOptions.itemsPerPage=e.defaultsPaginationOptions.itemsPerPage,e.paginationOptions.currentPage=e.defaultsPaginationOptions.currentPage,t.itemsPerPage&&(e.paginationOptions.itemsPerPage=t.itemsPerPage),t.page&&(!e.serverPagination&&(t.page-1)*e.paginationOptions.itemsPerPage>e.filtered.length?e.paginationOptions.currentPage=1:e.paginationOptions.currentPage=t.page),t.sort){var r=t.sort.split("-");e.sortOptions.predicate=decodeURIComponent(r[0]),e.sortOptions.direction=decodeURIComponent(r[1])}e.serverPagination||d()}function p(){var t="",i=a.search();Object.keys(i).forEach(function(e){t+=e+"="+i[e]+"&"}),t=t.slice(0,-1),!t&&e.sortOptions.predicate?e.sort(e.sortOptions.predicate,!0):e._gridOptions.getData("?"+t,function(t,i){e.filtered=t,e.paginationOptions.totalItems=i})}function d(){var t=Date.now(),i=!1;e._time={},e.sortOptions.predicate&&e.sortCache&&e.sortCache.predicate===e.sortOptions.predicate&&e.sortCache.direction===e.sortOptions.direction?(e.filtered=e.sortCache.data.slice(),i=!0):e.filtered=e._gridOptions.data.slice(),e._time.copy=Date.now()-t;var r=Date.now();g(),e._time.filters=Date.now()-r;var a=Date.now();e.sortOptions.predicate&&!i&&(e.filtered=n("orderBy")(e.filtered,e.sortOptions.predicate,"desc"===e.sortOptions.direction),e.sortCache={data:e.filtered.slice(),predicate:e.sortOptions.predicate,direction:e.sortOptions.direction}),e._time.sort=Date.now()-a,e._time.all=Date.now()-t,e.paginationOptions.totalItems=e.filtered.length}function g(){e.filters.forEach(function(t){var i=t.filterBy,r=t.model,n=t.isInScope?e.$eval(r):e.$parent.$eval(r),a=t.filterType;if(e.customFilters[r])e.filtered=e.customFilters[r](e.filtered,n,i);else if(n&&a){var s=o.getFilterByType(a);s&&(e.filtered=s(e.filtered,n,i))}})}e._gridOptions=e.$eval(r.attr("grid-options")),e._gridActions=e.$eval(r.attr("grid-actions")),e.serverPagination="true"===r.attr("server-pagination"),e.getDataDelay=r.attr("get-delay")||350,e._gridActions||(e.$parent.$eval(r.attr("grid-actions")+"= {}"),e._gridActions=e.$parent.$eval(r.attr("grid-actions"))),e._gridOptions.grid=e,e.filtered=e._gridOptions.data.slice(),e.paginationOptions=e._gridOptions.pagination?angular.copy(e._gridOptions.pagination):{},e.defaultsPaginationOptions={itemsPerPage:e.paginationOptions.itemsPerPage,currentPage:e.paginationOptions.currentPage||1},e.paginationOptions=angular.copy(e.defaultsPaginationOptions),e.sortOptions=e._gridOptions.sort?angular.copy(e._gridOptions.sort):{},e.customFilters=e._gridOptions.customFilters?angular.copy(e._gridOptions.customFilters):{},e.urlSync=e._gridOptions.urlSync,e.$watchCollection("_gridOptions.data",function(i){i&&i.length>-1&&(e.sortCache={},e.filtered=e._gridOptions.data.slice(),e.filters.forEach(function(i){"select"===i.filterType&&(e[i.model+"Options"]=t(e.filtered,i.filterBy))}),e.urlSync?l():d())}),e.sort=function(t,i){if(!i){var r=e.sortOptions.predicate===t&&"desc"===e.sortOptions.direction?"asc":"desc";e.sortOptions.direction=r,e.sortOptions.predicate=t}e.paginationOptions.currentPage=1,e.reloadGrid(i)},e.filter=function(){e.paginationOptions.currentPage=1,e.reloadGrid()},e.$on("$locationChangeSuccess",function(){s()}),e.$on("$stateChangeSuccess",function(t,e){s()}),e.reloadGrid=function(t){e.urlSync||e.serverPagination?c(t):d(),i.$broadcast("gridReloaded")},e._gridActions.refresh=e.reloadGrid,e._gridActions.filter=e.filter,e._gridActions.sort=e.sort}]).directive("gridItem",["$compile",function(t){return{restrict:"EA",terminal:!0,scope:!1,link:function(e,i,r,n,a){e.serverPagination?i.attr("ng-repeat","item in filtered"):i.attr("ng-repeat","item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage track by $index"),i.removeAttr("grid-item");var o=i[0].outerHTML;i.replaceWith(t(o)(e))}}}]).directive("gridData",["$compile","$animate",function(e){return{restrict:"EA",scope:!0,controller:"gridController",link:function(i,r,n){var a=[],o=r.parent(),s=n.id,c="true"===n.serverPagination;i.serverPagination=c,angular.forEach(angular.element(o[0].querySelectorAll("[sortable]")),function(t){var r=angular.element(t),n=r.attr("sortable");r.attr("ng-class","{'sort-ascent' : sortOptions.predicate ==='"+n+"' && sortOptions.direction === 'asc', 'sort-descent' : sortOptions.predicate === '"+n+"' && sortOptions.direction === 'desc'}"),r.attr("ng-click","sort('"+n+"')"),e(r)(i)}),angular.forEach(document.querySelectorAll("[filter-by]"),function(e){var n=angular.element(e),o=n.attr("filter-by"),c=document.querySelectorAll("[grid-data]")[0],l=c.querySelectorAll('[filter-by="'+o+'"]').length>0,p=n.attr("filter-type")||"",d=n.attr("ng-model"),g=n.attr("disable-url");s&&n.attr("grid-id")&&s!=n.attr("grid-id")||("select"!==p||(i[d+"Options"]=t(i.$eval(r.attr("grid-options")+".data"),o)),!~p.indexOf("date")||n.attr("ng-focus")||n.attr("ng-blur")||(n.attr("ng-focus","filter('{"+d+" : this."+d+"}')"),n.attr("ng-blur","filter('{"+d+" : this."+d+"}')")),d||(d=o,n.attr("ng-model",o),n.attr("ng-change","filter()")),a.push({model:d,isInScope:l,filterBy:o,filterType:p,disableUrl:g}))}),i.filters=a}}}]).factory("filtersFactory",function(){function t(t,e,i){return t.filter(function(t){return!e||!t[i]||t[i]===e})}function e(t,e,i){return t.filter(function(t){return e&&t[i]?~(t[i]+"").toLowerCase().indexOf((e+"").toLowerCase()):!!t[i]})}function i(t,e,i){return e=new Date(e).getTime(),t.filter(function(t){return!e||!t[i]||t[i]<=e+86399999})}function r(t,e,i){return e=new Date(e).getTime(),t.filter(function(t){return!e||!t[i]||t[i]>=e})}return{getFilterByType:function(n){switch(n){case"select":return t;case"text":return e;case"dateTo":return i;case"dateFrom":return r;default:return null}}}})}(); \ No newline at end of file diff --git a/dist/dataGridUtils.js b/dist/dataGridUtils.js new file mode 100644 index 0000000..06f4061 --- /dev/null +++ b/dist/dataGridUtils.js @@ -0,0 +1,89 @@ +(function () { + 'use strict'; + angular.module('dataGridUtils', []); +})(); +(function () { + 'use strict'; + angular.module('dataGridUtils.fixedHeader', []) + .directive('fixedHeader', FixedHeader); + + FixedHeader.$inject = ['$window', '$timeout']; + + function FixedHeader($window, $timeout) { + var window = angular.element($window); + + return { + restrict: 'A', + link: link + }; + + function link(scope, element, attrs) { + var elementOffsetFrom = attrs.offsetFromElement ? + document.querySelector(attrs.offsetFromElement) : + window; + + function onResize() { + var thElements = element.find("th"); + for (var i = 0; i < thElements.length; i++) { + var tdElement = element.find("td").eq(i)[0]; + if (!tdElement) { + return; + } + var tdElementWidth = tdElement.offsetWidth; + angular.element(thElements[i]).css({'width': tdElementWidth + 'px'}); + } + } + + function bindFixedToHeader() { + var thead = element.find("thead"), + tbody = element.find("tbody"), + tbodyLeftPos = tbody[0].getBoundingClientRect().left; + thead.addClass('fixed-header'); + if (attrs.offsetFromElement) { + var topElement = document.querySelector(attrs.offsetFromElement); + var offset = topElement.getBoundingClientRect().top + topElement.offsetHeight; + thead.css({"top": offset}); + } + thead.css({"left": tbodyLeftPos}); + tbody.addClass("tbody-offset"); + } + + function unBindFixedToHeader() { + var thead = element.find("thead"), + tbody = element.find("tbody"); + thead.removeClass('fixed-header'); + thead.css({"left": ""}); + thead.css({"top": ""}); + tbody.removeClass("tbody-offset"); + } + + function onScroll() { + var offset = attrs.offsetFromElement ? + elementOffsetFrom.getBoundingClientRect().top + elementOffsetFrom.offsetHeight : + $window.pageYOffset, + tableOffsetTop = attrs.offsetFromElement ? + element[0].getBoundingClientRect().top : + element[0].getBoundingClientRect().top + offset, + tableOffsetBottom = tableOffsetTop + element[0].offsetHeight - element.find("thead")[0].offsetHeight; + + if (offset < tableOffsetTop || offset > tableOffsetBottom) { + unBindFixedToHeader(); + } + else if (offset >= tableOffsetTop && offset <= tableOffsetBottom) { + bindFixedToHeader(); + } + onResize(); + } + + scope.$on('gridReloaded', function () { + $timeout(function () { + onResize(); + onScroll(); + }, 0); + }); + window.on('resize', onResize); + window.on('scroll', onScroll); + } + } + +})(); \ No newline at end of file diff --git a/dist/dataGridUtils.min.js b/dist/dataGridUtils.min.js new file mode 100644 index 0000000..fa1410f --- /dev/null +++ b/dist/dataGridUtils.min.js @@ -0,0 +1 @@ +!function(){"use strict";angular.module("dataGridUtils",[])}(),function(){"use strict";function e(e,t){function n(n,f,i){function d(){for(var e=f.find("th"),t=0;to?s():t>=n&&t<=o&&r(),d()}var l=i.offsetFromElement?document.querySelector(i.offsetFromElement):o;n.$on("gridReloaded",function(){t(function(){d(),a()},0)}),o.on("resize",d),o.on("scroll",a)}var o=angular.element(e);return{restrict:"A",link:n}}angular.module("dataGridUtils.fixedHeader",[]).directive("fixedHeader",e),e.$inject=["$window","$timeout"]}(); \ No newline at end of file diff --git a/dist/loading-bar.min.js b/dist/loading-bar.min.js index f0fdc27..2d76439 100644 --- a/dist/loading-bar.min.js +++ b/dist/loading-bar.min.js @@ -1 +1 @@ -!function(){"use strict";angular.module("angular-loading-bar",["cfp.loadingBarInterceptor"]),angular.module("chieffancypants.loadingBar",["cfp.loadingBarInterceptor"]),angular.module("cfp.loadingBarInterceptor",["cfp.loadingBar"]).config(["$httpProvider",function(e){var n=["$q","$cacheFactory","$timeout","$rootScope","$log","cfpLoadingBar",function(n,t,a,r,i,c){function o(){a.cancel(d),c.complete(),u=0,s=0}function l(n){var a,r=t.get("$http"),i=e.defaults;!n.cache&&!i.cache||n.cache===!1||"GET"!==n.method&&"JSONP"!==n.method||(a=angular.isObject(n.cache)?n.cache:angular.isObject(i.cache)?i.cache:r);var c=void 0!==a?void 0!==a.get(n.url):!1;return void 0!==n.cached&&c!==n.cached?n.cached:(n.cached=c,c)}var d,s=0,u=0,g=c.latencyThreshold;return{request:function(e){return e.ignoreLoadingBar||l(e)||(r.$broadcast("cfpLoadingBar:loading",{url:e.url}),0===s&&(d=a(function(){c.start()},g)),s++,c.set(u/s)),e},response:function(e){return e&&e.config?(e.config.ignoreLoadingBar||l(e.config)||(u++,r.$broadcast("cfpLoadingBar:loaded",{url:e.config.url,result:e}),u>=s?o():c.set(u/s)),e):(i.error("Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),e)},responseError:function(e){return e&&e.config?(e.config.ignoreLoadingBar||l(e.config)||(u++,r.$broadcast("cfpLoadingBar:loaded",{url:e.config.url,result:e}),u>=s?o():c.set(u/s)),n.reject(e)):(i.error("Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),n.reject(e))}}}];e.interceptors.push(n)}]),angular.module("cfp.loadingBar",[]).provider("cfpLoadingBar",function(){this.includeSpinner=!0,this.includeBar=!0,this.latencyThreshold=100,this.startSize=.02,this.parentSelector="body",this.spinnerTemplate='
',this.loadingBarTemplate='
',this.$get=["$injector","$document","$timeout","$rootScope",function(e,n,t,a){function r(){s||(s=e.get("$animate"));var r=n.find(h).eq(0);t.cancel(g),m||(a.$broadcast("cfpLoadingBar:started"),m=!0,b&&s.enter(p,r,angular.element(r[0].lastChild)),$&&s.enter(v,r,angular.element(r[0].lastChild)),i(S))}function i(e){if(m){var n=100*e+"%";f.css("width",n),B=e,t.cancel(u),u=t(function(){c()},250)}}function c(){if(!(o()>=1)){var e=0,n=o();e=n>=0&&.25>n?(3*Math.random()+3)/100:n>=.25&&.65>n?3*Math.random()/100:n>=.65&&.9>n?2*Math.random()/100:n>=.9&&.99>n?.005:0;var t=o()+e;i(t)}}function o(){return B}function l(){B=0,m=!1}function d(){s||(s=e.get("$animate")),a.$broadcast("cfpLoadingBar:completed"),i(1),t.cancel(g),g=t(function(){var e=s.leave(p,l);e&&e.then&&e.then(l),s.leave(v)},500)}var s,u,g,h=this.parentSelector,p=angular.element(this.loadingBarTemplate),f=p.find("div").eq(0),v=angular.element(this.spinnerTemplate),m=!1,B=0,$=this.includeSpinner,b=this.includeBar,S=this.startSize;return{start:r,set:i,status:o,inc:c,complete:d,includeSpinner:this.includeSpinner,latencyThreshold:this.latencyThreshold,parentSelector:this.parentSelector,startSize:this.startSize}}]})}(); \ No newline at end of file +!function(){"use strict";angular.module("angular-loading-bar",["cfp.loadingBarInterceptor"]),angular.module("chieffancypants.loadingBar",["cfp.loadingBarInterceptor"]),angular.module("cfp.loadingBarInterceptor",["cfp.loadingBar"]).config(["$httpProvider",function(e){var n=["$q","$cacheFactory","$timeout","$rootScope","$log","cfpLoadingBar",function(n,t,a,r,i,c){function o(){a.cancel(d),c.complete(),u=0,s=0}function l(n){var a,r=t.get("$http"),i=e.defaults;!n.cache&&!i.cache||n.cache===!1||"GET"!==n.method&&"JSONP"!==n.method||(a=angular.isObject(n.cache)?n.cache:angular.isObject(i.cache)?i.cache:r);var c=void 0!==a&&void 0!==a.get(n.url);return void 0!==n.cached&&c!==n.cached?n.cached:(n.cached=c,c)}var d,s=0,u=0,g=c.latencyThreshold;return{request:function(e){return e.ignoreLoadingBar||l(e)||(r.$broadcast("cfpLoadingBar:loading",{url:e.url}),0===s&&(d=a(function(){c.start()},g)),s++,c.set(u/s)),e},response:function(e){return e&&e.config?(e.config.ignoreLoadingBar||l(e.config)||(u++,r.$broadcast("cfpLoadingBar:loaded",{url:e.config.url,result:e}),u>=s?o():c.set(u/s)),e):(i.error("Broken interceptor detected: Config object not supplied in response:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),e)},responseError:function(e){return e&&e.config?(e.config.ignoreLoadingBar||l(e.config)||(u++,r.$broadcast("cfpLoadingBar:loaded",{url:e.config.url,result:e}),u>=s?o():c.set(u/s)),n.reject(e)):(i.error("Broken interceptor detected: Config object not supplied in rejection:\n https://github.com/chieffancypants/angular-loading-bar/pull/50"),n.reject(e))}}}];e.interceptors.push(n)}]),angular.module("cfp.loadingBar",[]).provider("cfpLoadingBar",function(){this.includeSpinner=!0,this.includeBar=!0,this.latencyThreshold=100,this.startSize=.02,this.parentSelector="body",this.spinnerTemplate='
',this.loadingBarTemplate='
',this.$get=["$injector","$document","$timeout","$rootScope",function(e,n,t,a){function r(){s||(s=e.get("$animate"));var r=n.find(h).eq(0);t.cancel(g),m||(a.$broadcast("cfpLoadingBar:started"),m=!0,b&&s.enter(p,r,angular.element(r[0].lastChild)),$&&s.enter(v,r,angular.element(r[0].lastChild)),i(S))}function i(e){if(m){var n=100*e+"%";f.css("width",n),B=e,t.cancel(u),u=t(function(){c()},250)}}function c(){if(!(o()>=1)){var e=0,n=o();e=n>=0&&n<.25?(3*Math.random()+3)/100:n>=.25&&n<.65?3*Math.random()/100:n>=.65&&n<.9?2*Math.random()/100:n>=.9&&n<.99?.005:0;var t=o()+e;i(t)}}function o(){return B}function l(){B=0,m=!1}function d(){s||(s=e.get("$animate")),a.$broadcast("cfpLoadingBar:completed"),i(1),t.cancel(g),g=t(function(){var e=s.leave(p,l);e&&e.then&&e.then(l),s.leave(v)},500)}var s,u,g,h=this.parentSelector,p=angular.element(this.loadingBarTemplate),f=p.find("div").eq(0),v=angular.element(this.spinnerTemplate),m=!1,B=0,$=this.includeSpinner,b=this.includeBar,S=this.startSize;return{start:r,set:i,status:o,inc:c,complete:d,includeSpinner:this.includeSpinner,latencyThreshold:this.latencyThreshold,parentSelector:this.parentSelector,startSize:this.startSize}}]})}(); \ No newline at end of file diff --git a/dist/pagination.min.js b/dist/pagination.min.js index 3dcecb4..eea082a 100644 --- a/dist/pagination.min.js +++ b/dist/pagination.min.js @@ -1 +1 @@ -!function(){"use strict";angular.module("paging",[]).factory("paging",["$parse",function(e){return{create:function(a,n,t){a.setNumPages=t.numPages?e(t.numPages).assign:angular.noop,a.ngModelCtrl={$setViewValue:angular.noop},a.init=function(i,r){a.ngModelCtrl=i,a.config=r,i.$render=function(){a.render()},t.itemsPerPage?n.$parent.$watch(e(t.itemsPerPage),function(e){a.itemsPerPage=parseInt(e,10),n.totalPages=a.calculateTotalPages(),a.updatePage()}):a.itemsPerPage=r.itemsPerPage,n.$watch("totalItems",function(e,t){(angular.isDefined(e)||e!==t)&&(n.totalPages=a.calculateTotalPages(),a.updatePage())})},a.calculateTotalPages=function(){var e=a.itemsPerPage<1?1:Math.ceil(n.totalItems/a.itemsPerPage);return Math.max(e||0,1)},a.render=function(){n.page=parseInt(a.ngModelCtrl.$viewValue,10)||1},n.selectPage=function(e,t){t&&t.preventDefault();var i=!n.ngDisabled||!t;i&&n.page!==e&&e>0&&e<=n.totalPages&&(t&&t.target&&t.target.blur(),a.ngModelCtrl.$setViewValue(e),a.ngModelCtrl.$render())},n.getText=function(e){return n[e+"Text"]||a.config[e+"Text"]},n.noPrevious=function(){return 1===n.page},n.noNext=function(){return n.page===n.totalPages},a.updatePage=function(){a.setNumPages(n.$parent,n.totalPages),n.page>n.totalPages?n.selectPage(n.totalPages):a.ngModelCtrl.$render()}}}}]),angular.module("pagination",["paging"]).controller("PaginationController",["$scope","$attrs","$parse","paging","paginationConfig",function(e,a,n,t,i){function r(e,a,n){return{number:e,text:a,active:n}}function s(e,a){var n=[],t=1,i=a,s=angular.isDefined(g)&&a>g;s&&(o?(t=Math.max(e-Math.floor(g/2),1),i=t+g-1,i>a&&(i=a,t=i-g+1)):(t=(Math.ceil(e/g)-1)*g+1,i=Math.min(t+g-1,a)));for(var l=t;i>=l;l++){var p=r(l,l,l===e);n.push(p)}if(s&&g>0&&(!o||u||c)){if(t>1){if(!c||t>3){var f=r(t-1,"...",!1);n.unshift(f)}if(c){if(3===t){var d=r(2,"2",!1);n.unshift(d)}var P=r(1,"1",!1);n.unshift(P)}}if(a>i){if(!c||a-2>i){var v=r(i+1,"...",!1);n.push(v)}if(c){if(i===a-2){var m=r(a-1,a-1,!1);n.push(m)}var $=r(a,a,!1);n.push($)}}}return n}var l=this,g=angular.isDefined(a.maxSize)?e.$parent.$eval(a.maxSize):i.maxSize,o=angular.isDefined(a.rotate)?e.$parent.$eval(a.rotate):i.rotate,u=angular.isDefined(a.forceEllipses)?e.$parent.$eval(a.forceEllipses):i.forceEllipses,c=angular.isDefined(a.boundaryLinkNumbers)?e.$parent.$eval(a.boundaryLinkNumbers):i.boundaryLinkNumbers;e.boundaryLinks=angular.isDefined(a.boundaryLinks)?e.$parent.$eval(a.boundaryLinks):i.boundaryLinks,e.directionLinks=angular.isDefined(a.directionLinks)?e.$parent.$eval(a.directionLinks):i.directionLinks,t.create(this,e,a),a.maxSize&&e.$parent.$watch(n(a.maxSize),function(e){g=parseInt(e,10),l.render()});var p=this.render;this.render=function(){p(),e.page>0&&e.page<=e.totalPages&&(e.pages=s(e.page,e.totalPages))}}]).constant("paginationConfig",{itemsPerPage:10,boundaryLinks:!1,boundaryLinkNumbers:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0,forceEllipses:!1}).directive("gridPagination",["$parse","paginationConfig",function(e,a){return{scope:{totalItems:"=",firstText:"@",previousText:"@",nextText:"@",lastText:"@",ngDisabled:"="},require:["gridPagination","?ngModel"],controller:"PaginationController",controllerAs:"pagination",templateUrl:function(e,a){return a.templateUrl||"src/template/pagination/pagination.html"},replace:!0,link:function(e,n,t,i){var r=i[0],s=i[1];s&&r.init(s,a)}}}]).run(["$templateCache",function(e){e.put("src/template/pagination/pagination.html","
")}])}(); \ No newline at end of file +!function(){"use strict";angular.module("paging",[]).factory("paging",["$parse",function(e){return{create:function(a,n,t){a.setNumPages=t.numPages?e(t.numPages).assign:angular.noop,a.ngModelCtrl={$setViewValue:angular.noop},a.init=function(i,r){a.ngModelCtrl=i,a.config=r,i.$render=function(){a.render()},t.itemsPerPage?n.$parent.$watch(e(t.itemsPerPage),function(e){a.itemsPerPage=parseInt(e,10),n.totalPages=a.calculateTotalPages(),a.updatePage()}):a.itemsPerPage=r.itemsPerPage,n.$watch("totalItems",function(e,t){(angular.isDefined(e)||e!==t)&&(n.totalPages=a.calculateTotalPages(),a.updatePage())})},a.calculateTotalPages=function(){var e=a.itemsPerPage<1?1:Math.ceil(n.totalItems/a.itemsPerPage);return Math.max(e||0,1)},a.render=function(){n.page=parseInt(a.ngModelCtrl.$viewValue,10)||1},n.selectPage=function(e,t){t&&t.preventDefault();var i=!n.ngDisabled||!t;i&&n.page!==e&&e>0&&e<=n.totalPages&&(t&&t.target&&t.target.blur(),a.ngModelCtrl.$setViewValue(e),a.ngModelCtrl.$render())},n.getText=function(e){return n[e+"Text"]||a.config[e+"Text"]},n.noPrevious=function(){return 1===n.page},n.noNext=function(){return n.page===n.totalPages},a.updatePage=function(){a.setNumPages(n.$parent,n.totalPages),n.page>n.totalPages?n.selectPage(n.totalPages):a.ngModelCtrl.$render()}}}}]),angular.module("pagination",["paging"]).controller("PaginationController",["$scope","$attrs","$parse","paging","paginationConfig",function(e,a,n,t,i){function r(e,a,n){return{number:e,text:a,active:n}}function s(e,a){var n=[],t=1,i=a,s=angular.isDefined(g)&&ga&&(i=a,t=i-g+1)):(t=(Math.ceil(e/g)-1)*g+1,i=Math.min(t+g-1,a)));for(var l=t;l<=i;l++){var p=r(l,l,l===e);n.push(p)}if(s&&g>0&&(!o||u||c)){if(t>1){if(!c||t>3){var f=r(t-1,"...",!1);n.unshift(f)}if(c){if(3===t){var d=r(2,"2",!1);n.unshift(d)}var P=r(1,"1",!1);n.unshift(P)}}if(i0&&e.page<=e.totalPages&&(e.pages=s(e.page,e.totalPages))}}]).constant("paginationConfig",{itemsPerPage:10,boundaryLinks:!1,boundaryLinkNumbers:!1,directionLinks:!0,firstText:"First",previousText:"Previous",nextText:"Next",lastText:"Last",rotate:!0,forceEllipses:!1}).directive("gridPagination",["$parse","paginationConfig",function(e,a){return{scope:{totalItems:"=",firstText:"@",previousText:"@",nextText:"@",lastText:"@",ngDisabled:"="},require:["gridPagination","?ngModel"],controller:"PaginationController",controllerAs:"pagination",templateUrl:function(e,a){return a.templateUrl||"src/template/pagination/pagination.html"},replace:!0,link:function(e,n,t,i){var r=i[0],s=i[1];s&&r.init(s,a)}}}]).run(["$templateCache",function(e){e.put("src/template/pagination/pagination.html","")}])}(); \ No newline at end of file diff --git a/gulpfile.js b/gulpfile.js index d3a2af8..cea1115 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -21,7 +21,7 @@ } gulp.task('js', function () { - gulp.src(['./src/**/*.js']) + gulp.src(['./src/js/vendors/*.js', './src/js/*.js']) .pipe(rename({dirname: ''})) .pipe(gulp.dest('./dist')) .pipe(uglify()) @@ -29,6 +29,15 @@ suffix: ".min" })) .pipe(gulp.dest('./dist')); + + gulp.src(['./src/js/directives/**/*.js']) + .pipe(concat('dataGridUtils.js')) + .pipe(gulp.dest('./dist')) + .pipe(uglify()) + .pipe(rename({ + suffix: ".min" + })) + .pipe(gulp.dest('./dist')); }); gulp.task('sass', function () { @@ -41,6 +50,15 @@ gulp.src('./demo/100k/scss/angular-data-grid.bootstrap.scss') .pipe(sass().on('error', sass.logError)) .pipe(gulp.dest('./demo/100k/css/')); + gulp.src('./demo/fixed-header/scss/fixed-header.bootstrap.scss') + .pipe(sass().on('error', sass.logError)) + .pipe(gulp.dest('./demo/fixed-header/css/')); + gulp.src('./demo/fixed-header/scss/fixed-header.material.scss') + .pipe(sass().on('error', sass.logError)) + .pipe(gulp.dest('./demo/fixed-header/css/')); + gulp.src('./src/js/directives/fixedHeader/fixed-header.scss') + .pipe(sass().on('error', sass.logError)) + .pipe(gulp.dest('./dist/css/fixedHeader/')); }); gulp.task('build', ['js', 'sass']); diff --git a/index.js b/index.js new file mode 100644 index 0000000..6b85ad2 --- /dev/null +++ b/index.js @@ -0,0 +1,7 @@ +require('./dist/dataGrid'); +require('./dist/pagination'); + +module.exports = { + dataGrid: 'dataGrid', + pagination: 'pagination', +}; diff --git a/package.json b/package.json index 3e5963a..6c7b4de 100644 --- a/package.json +++ b/package.json @@ -1,11 +1,11 @@ { "name": "angular-data-grid", - "version": "0.1.0", + "version": "1.0.0", "scripts": { "start": "gulp serve", "prebuild": "npm install" }, - "dependencies": { + "devDependencies": { "browser-sync": "^2.10.0", "gulp": "^3.9.0", "gulp-concat": "^2.6.0", @@ -14,21 +14,24 @@ "gulp-sass": "^2.1.0", "gulp-uglify": "^1.4.2" }, - "description": "Light, flexible and performant Data Grid for AngularJS apps, with built-in sorting, pagination and filtering options, unified API for client-side and server-side data fetching, \r seamless synchronization with browser address bar and total freedom in mark-up and styling suitable for your application. Angular 1.3 - 1.5 compliant.", - "main": "index.html", - "devDependencies": {}, + "description": "Light, flexible and performant Data Grid for AngularJS apps, with built-in sorting, pagination and filtering options, unified API for client-side and server-side data fetching, \r seamless synchronization with browser address bar and total freedom in mark-up and styling suitable for your application. Angular 1.3 - 1.6 compliant.", + "main": "index.js", + "dependencies": {}, "repository": { "type": "git", "url": "git+https://github.com/angular-data-grid/angular-data-grid.github.io.git" }, "keywords": [ "angular data grid", + "angular-data-grid", + "angular grid", + "angular-grid", "data grid", "data grid for angular", "ng-data-grid", "ng-table", "angular table", - "bootstra data grid", + "bootstrap data grid", "material design grid", "data table" ], diff --git a/src/js/dataGrid.js b/src/js/dataGrid.js index 8917d18..d7ddb3f 100644 --- a/src/js/dataGrid.js +++ b/src/js/dataGrid.js @@ -12,7 +12,7 @@ return []; } }) - .controller('gridController', ['$scope', '$element', '$filter', '$location', 'filtersFactory', function ($scope, $element, $filter, $location, filtersFactory) { + .controller('gridController', ['$scope', '$rootScope', '$element', '$filter', '$location', 'filtersFactory', function ($scope, $rootScope, $element, $filter, $location, filtersFactory) { // values by default $scope._gridOptions = $scope.$eval($element.attr('grid-options')); $scope._gridActions = $scope.$eval($element.attr('grid-actions')); @@ -29,7 +29,7 @@ $scope.filtered = $scope._gridOptions.data.slice(); $scope.paginationOptions = $scope._gridOptions.pagination ? angular.copy($scope._gridOptions.pagination) : {}; $scope.defaultsPaginationOptions = { - itemsPerPage: $scope.paginationOptions.itemsPerPage || '10', + itemsPerPage: $scope.paginationOptions.itemsPerPage, currentPage: $scope.paginationOptions.currentPage || 1 }; $scope.paginationOptions = angular.copy($scope.defaultsPaginationOptions); @@ -37,8 +37,8 @@ $scope.customFilters = $scope._gridOptions.customFilters ? angular.copy($scope._gridOptions.customFilters) : {}; $scope.urlSync = $scope._gridOptions.urlSync; - $scope.$watch('_gridOptions.data', function (newValue) { - if (newValue && newValue.length) { + $scope.$watchCollection('_gridOptions.data', function (newValue) { + if (newValue && newValue.length > -1) { $scope.sortCache = {}; $scope.filtered = $scope._gridOptions.data.slice(); $scope.filters.forEach(function (filter) { @@ -48,7 +48,7 @@ }); if ($scope.urlSync) { - parseUrl($location.path()); + parseUrl(); } else { applyFilters(); } @@ -71,15 +71,11 @@ }; $scope.$on('$locationChangeSuccess', function () { - if ($scope.urlSync || $scope.serverPagination) { - if ($scope.serverPagination) { - clearTimeout($scope.getDataTimeout); - $scope.getDataTimeout = setTimeout(getData, $scope.getDataDelay); - } - if ($scope.filtered) { - parseUrl($location.path()); - } - } + onChangeStateOrLocation() + }); + + $scope.$on("$stateChangeSuccess", function (event, toState) { + onChangeStateOrLocation() }); $scope.reloadGrid = function (isDefaultSort) { @@ -88,12 +84,25 @@ } else { applyFilters(); } + $rootScope.$broadcast('gridReloaded'); }; $scope._gridActions.refresh = $scope.reloadGrid; $scope._gridActions.filter = $scope.filter; $scope._gridActions.sort = $scope.sort; + function onChangeStateOrLocation(){ + if ($scope.urlSync || $scope.serverPagination) { + if ($scope.serverPagination) { + clearTimeout($scope.getDataTimeout); + $scope.getDataTimeout = setTimeout(getData, $scope.getDataDelay); + } + if ($scope.filtered) { + parseUrl(); + } + } + } + function changePath(isDefaultSort) { var path, needApplyFilters = false; @@ -134,27 +143,21 @@ if (needApplyFilters) { applyFilters(); } - $location.path(path); + $location.search(path); if (isDefaultSort) { $scope.$apply(); } } function parseUrl() { - var url = $location.path().slice(1), - params = {}, + var params = $location.search(), customParams = {}; - $scope.params = params; - - url.split('&').forEach(function (urlParam) { - var param = urlParam.split('='); - params[param[0]] = param[1]; - if (param[0] !== 'page' && param[0] !== 'sort' && param[0] !== 'itemsPerPage') { - customParams[decodeURIComponent(param[0])] = decodeURIComponent(param[1]); - } + Object.keys(params).forEach(function(key) { + if (key !== 'page' && key !== 'sort' && key !== 'itemsPerPage') { + customParams[key] = params[key]; } - ); + }); //custom filters $scope.filters.forEach(function (filter) { @@ -216,7 +219,12 @@ } function getData() { - var url = $location.path().slice(1); + var url = ''; + var params = $location.search(); + Object.keys(params).forEach(function(key) { + url += key + '=' + params[key] + '&'; + }); + url = url.slice(0, -1); if (!url && $scope.sortOptions.predicate) { $scope.sort($scope.sortOptions.predicate, true); } else { @@ -282,6 +290,23 @@ }); } }]) + .directive('gridItem', ['$compile', function ($compile) { + return { + restrict: 'EA', + terminal:true, + scope: false, + link: function ($scope, element, attrs, ctrl, transclude) { + if ($scope.serverPagination) { + element.attr('ng-repeat', "item in filtered"); + } else { + element.attr('ng-repeat', "item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage track by $index"); + } + element.removeAttr('grid-item'); + var html = element[0].outerHTML; + element.replaceWith($compile(html)($scope)); + } + } + }]) .directive('gridData', ['$compile', '$animate', function ($compile) { return { restrict: 'EA', @@ -290,29 +315,27 @@ scope: true, controller: 'gridController', link: function ($scope, $element, attrs) { - var sorting = [], - filters = [], - rows = [], + var filters = [], directiveElement = $element.parent(), gridId = attrs.id, serverPagination = attrs.serverPagination === 'true'; + $scope.serverPagination = serverPagination; angular.forEach(angular.element(directiveElement[0].querySelectorAll('[sortable]')), function (sortable) { var element = angular.element(sortable), predicate = element.attr('sortable'); - sorting.push(element); element.attr('ng-class', "{'sort-ascent' : sortOptions.predicate ==='" + predicate + "' && sortOptions.direction === 'asc', 'sort-descent' : sortOptions.predicate === '" + predicate + "' && sortOptions.direction === 'desc'}"); element.attr('ng-click', "sort('" + predicate + "')"); $compile(element)($scope); }); - - angular.forEach(angular.element(document.querySelectorAll('[filter-by]')), function (filter) { + angular.forEach(document.querySelectorAll('[filter-by]'), function (filter) { var element = angular.element(filter), - isInScope = $element.find(element).length > 0, predicate = element.attr('filter-by'), + dataGridElement = document.querySelectorAll('[grid-data]')[0], + isInScope = dataGridElement.querySelectorAll('[filter-by="'+ predicate+'"]').length > 0, filterType = element.attr('filter-type') || '', urlName = element.attr('ng-model'), disableUrl = element.attr('disable-url'); @@ -348,19 +371,6 @@ }); }); - angular.forEach(angular.element(directiveElement[0].querySelectorAll('[grid-item]')), function (row) { - var element = angular.element(row); - rows.push(element); - if (serverPagination) { - element.attr('ng-repeat', "item in filtered"); - } else { - element.attr('ng-repeat', "item in filtered | startFrom:(paginationOptions.currentPage-1)*paginationOptions.itemsPerPage | limitTo:paginationOptions.itemsPerPage track by $index"); - } - $compile(element)($scope); - }); - - $scope.sorting = sorting; - $scope.rows = rows; $scope.filters = filters; } } diff --git a/src/js/directives/dataGridUtils.js b/src/js/directives/dataGridUtils.js new file mode 100644 index 0000000..11f7813 --- /dev/null +++ b/src/js/directives/dataGridUtils.js @@ -0,0 +1,4 @@ +(function () { + 'use strict'; + angular.module('dataGridUtils', []); +})(); \ No newline at end of file diff --git a/src/js/directives/fixedHeader/fixed-header.scss b/src/js/directives/fixedHeader/fixed-header.scss new file mode 100644 index 0000000..eeea5eb --- /dev/null +++ b/src/js/directives/fixedHeader/fixed-header.scss @@ -0,0 +1,15 @@ +//Here are described styles that are used bu fixed-header directive +.fixed-header { + top: 0; + position: fixed; + width: auto; + display: table; + z-index: 99; +} + +.tbody-offset { + &:before { + content: " "; + display: block; + } +} \ No newline at end of file diff --git a/src/js/directives/fixedHeader/fixedHeader.js b/src/js/directives/fixedHeader/fixedHeader.js new file mode 100644 index 0000000..8242357 --- /dev/null +++ b/src/js/directives/fixedHeader/fixedHeader.js @@ -0,0 +1,85 @@ +(function () { + 'use strict'; + angular.module('dataGridUtils.fixedHeader', []) + .directive('fixedHeader', FixedHeader); + + FixedHeader.$inject = ['$window', '$timeout']; + + function FixedHeader($window, $timeout) { + var window = angular.element($window); + + return { + restrict: 'A', + link: link + }; + + function link(scope, element, attrs) { + var elementOffsetFrom = attrs.offsetFromElement ? + document.querySelector(attrs.offsetFromElement) : + window; + + function onResize() { + var thElements = element.find("th"); + for (var i = 0; i < thElements.length; i++) { + var tdElement = element.find("td").eq(i)[0]; + if (!tdElement) { + return; + } + var tdElementWidth = tdElement.offsetWidth; + angular.element(thElements[i]).css({'width': tdElementWidth + 'px'}); + } + } + + function bindFixedToHeader() { + var thead = element.find("thead"), + tbody = element.find("tbody"), + tbodyLeftPos = tbody[0].getBoundingClientRect().left; + thead.addClass('fixed-header'); + if (attrs.offsetFromElement) { + var topElement = document.querySelector(attrs.offsetFromElement); + var offset = topElement.getBoundingClientRect().top + topElement.offsetHeight; + thead.css({"top": offset}); + } + thead.css({"left": tbodyLeftPos}); + tbody.addClass("tbody-offset"); + } + + function unBindFixedToHeader() { + var thead = element.find("thead"), + tbody = element.find("tbody"); + thead.removeClass('fixed-header'); + thead.css({"left": ""}); + thead.css({"top": ""}); + tbody.removeClass("tbody-offset"); + } + + function onScroll() { + var offset = attrs.offsetFromElement ? + elementOffsetFrom.getBoundingClientRect().top + elementOffsetFrom.offsetHeight : + $window.pageYOffset, + tableOffsetTop = attrs.offsetFromElement ? + element[0].getBoundingClientRect().top : + element[0].getBoundingClientRect().top + offset, + tableOffsetBottom = tableOffsetTop + element[0].offsetHeight - element.find("thead")[0].offsetHeight; + + if (offset < tableOffsetTop || offset > tableOffsetBottom) { + unBindFixedToHeader(); + } + else if (offset >= tableOffsetTop && offset <= tableOffsetBottom) { + bindFixedToHeader(); + } + onResize(); + } + + scope.$on('gridReloaded', function () { + $timeout(function () { + onResize(); + onScroll(); + }, 0); + }); + window.on('resize', onResize); + window.on('scroll', onScroll); + } + } + +})(); \ No newline at end of file diff --git a/src/js/vendors/JSONToCSVConvertor.js b/src/js/vendors/JSONToCSVConvertor.js new file mode 100644 index 0000000..3fce1b6 --- /dev/null +++ b/src/js/vendors/JSONToCSVConvertor.js @@ -0,0 +1,84 @@ +function JSONToCSVConvertor(JSONData, ReportTitle, ShowLabel) { + //If JSONData is not an object then JSON.parse will parse the JSON string in an Object + var arrData = typeof JSONData != 'object' ? JSON.parse(JSONData) : JSONData; + + var CSV = ''; + //Set Report title in first row or line + + CSV += ReportTitle + '\r\n\n'; + + var currentDate = new Date(); + + CSV += currentDate + '\r\n\n'; + + //This condition will generate the Label/Header + if (ShowLabel) { + var row = ""; + + //This loop will extract the label from 1st index of on array + for (var index in arrData[0]) { + + //Now convert each value to string and comma-seprated + row += index + ','; + } + + row = row.slice(0, -1); + + //append Label row with line break + CSV += row + '\r\n'; + } + + //1st loop is to extract each row + for (var i = 0; i < arrData.length; i++) { + var row = ""; + + //2nd loop will extract each column and convert it in string comma-seprated + for (var index in arrData[i]) { + row += '"' + arrData[i][index] + '",'; + } + + row.slice(0, row.length - 1); + + //add a line break after each row + CSV += row + '\r\n'; + } + + if (CSV == '') { + alert("Invalid data"); + return; + } + + //Generate a file name + var fileName = ""; + //this will remove the blank-spaces from the title and replace it with an underscore + fileName += ReportTitle.replace(/ /g, "_"); + + //Initialize file format you want csv or xls + var uri = 'data:text/csv;charset=utf-8,' + escape(CSV); + + // Now the little tricky part. + // you can use either>> window.open(uri); + // but this will not work in some browsers + // or you will not get the correct file extension + + //this trick will generate a temp tag + + if (navigator.msSaveBlob) { + uri = 'data:text/csv;charset=utf-8,' + CSV; + navigator.msSaveBlob(new Blob([uri], {type: 'text/csv;charset=utf-8;'}), fileName + ".csv"); + } + + else { + var link = document.createElement("a"); + link.href = uri; + + //set the visibility hidden so it will not effect on your web-layout + link.style = "visibility:hidden"; + link.download = fileName + ".csv"; + + //this part will append the anchor tag and remove it after automatic click + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } +} \ No newline at end of file