AngularJS grid - meetbill/butterfly-fe GitHub Wiki
- 0 ng-grid 与 ui-grid 选择
- 1 ng-grid【弃用】
- 2 Module name has changed from nggrid to ui.grid
- 3 ng-grid option
- 4 tips
- 5 ui-grid 使用
- 6 常见问题
ng-grid 是实现了基本的表格样式需求,ui-grid 要更加强大,里面封装了很多指令,实现表格换行、拖拽等更高级的表格功能
ng-grid 表格中内容无法复制,表格宽度无法动态调整等等,所以建议还是使用新的 ui-grid
Upgrading from ng-grid 2.0.x to ui-grid 3.0
1. <div class="gridStyle" ng-grid="gridOptions"></div>
gridOptions 就是绑定表格的变量。
2. 可以先给表格设置一个基本的样式,如:
.gridStyle {
border: 1px solid rgb(212,212,212);
width: 400px;
height: 300px
}
3. 在控制器中添加数据:
$scope.myData = [{name: "Moroni", age: 50},
{name: "Tiancum", age: 43},
{name: "Jacob", age: 27},
{name: "Nephi", age: 29},
{name: "Enos", age: 34}];
4. 在同个控制器下初始化表格:
$scope.gridOptions = { data: 'myData' };
totalServerItems: 'totalServerItems',
if (typeof options.totalServerItems === "string") {
$scope.$on('$destroy', $scope.$parent.$watch(options.totalServerItems, function (newTotal, oldTotal) {
if (!angular.isDefined(newTotal)) {
$scope.totalServerItems = 0;
}
else {
$scope.totalServerItems = newTotal;
}
}));
}
else {
$scope.totalServerItems = 0;
}
Directive name has changed from ng-grid to ui-grid.
Before:
<div ng-grid="{ data: data }"></div>angular.module('yourModule', ['ngGrid'];After:
<div ui-grid="{ data: data }"></div>angular.module('yourModule', ['ui.grid'];ColumnDefs are now always watched via $watchCollection.
Before:
$scope.myColDefs = {[...]};
$scope.gridOptions.columnDefs = 'myColDefs'After:
$scope.gridOptions.columnDefs = $scope.myColDefs = [...];
or
$scope.gridOptions.columnDefs = [...];Before:
$scope.gridOptions = {
columnDefs: [
{ displayName: 'Edit' }
],
data: myData
};After:
$scope.gridOptions = {
columnDefs: [
{ name: 'edit', displayName: 'Edit' }
],
data: myData
};You can no longer access data or functions directly on the parent scope. You must use grid.appScope to get a reference to the parent scope
Before:
$scope.gridOptions = {
columnDefs = [
{ name: 'edit', displayName: 'Edit', cellTemplate: '<button ng-click="edit(row.entity)" >Edit</button>' }
],
data: myData
};
$scope.edit = function( entity ) {
...some custom function using entity...
};<div ng-grid="gridOptions" ></div>After:
$scope.gridScope = $scope;
$scope.gridOptions = {
columnDefs = [
{ name: 'edit', displayName: 'Edit', cellTemplate: '<button ng-click="grid.appScope.edit(row.entity)" >Edit</button>' }
],
data: myData
};
$scope.edit = function( entity ) {
...some custom function using entity...
};row.entity
row.entity 会获取到此行的对象,,,,, 添加按钮的时候非常有用的对象
Refer to the tutorials and API documentation at http://ui-grid.info/docs/ for more detail, an example provided below is column resizing. The plugins are available in the base javascript, using them requires only including the appropriate directive in the grid declaration:
After:
<div ui-grid="gridOptions" ui-grid-resize-columns ></div>ng-grid 的 option 包括 Grid Options 和 ColumnDefs Options
$scope.gridOptions
pagingOptions
{
pageSizes : 页面大小列表
pageSize : 当前选定的页面大小
currentPage : 当前页
}
totalServerItems
num: 总数
filterOptions
{
filterText: '',
useExternalFilter: false
}
data
[]: 在网格中显示的数据。数组中的每个项都映射到要显示的行。
Ps:data: 'myData'
enablePaging
true: 是否启用服务器端分页功能
Ps: 如果设置为 ture ,则会显示分页及切换的按钮
源码:
<div class="ngPagerContainer" style="float: right; margin-top: 10px;" ng-show="enablePaging" ng-class="{'ngNoMultiSelect': !multiSelect}">
<div style="float:left; margin-right: 10px;" class="ngRowCountPicker">"
<span style="float: left; margin-top: 3px;" class="ngLabel">__i18n.ngPageSizeLabel__</span>
<select style="float: left;height: 27px; width: 100px" ng-model="pagingOptions.pageSize" >
<option ng-repeat="size in pagingOptions.pageSizes">__size__</option>
</select>
</div>
<div style="float:left; margin-right: 10px; line-height:25px;" class="ngPagerControl" style="float: left; min-width: 135px;">
// 跳到第一页
<button type="button" class="ngPagerButton" ng-click="pageToFirst()" ng-disabled="cantPageBackward()" title="__i18n.ngPagerFirstTitle__"><div class="ngPagerFirstTriangle"><div class="ngPagerFirstBar"></div></div></button>
// 上一页
<button type="button" class="ngPagerButton" ng-click="pageBackward()" ng-disabled="cantPageBackward()" title="__i18n.ngPagerPrevTitle__"><div class="ngPagerFirstTriangle ngPagerPrevTriangle"></div></button>
<input class="ngPagerCurrent" min="1" max="__currentMaxPages__" type="number" style="width:50px; height: 24px; margin-top: 1px; padding: 0 4px;" ng-model="pagingOptions.currentPage"/>
<span class="ngGridMaxPagesNumber" ng-show="maxPages() > 0"> __maxPages()__</span>
// 下一页
<button type="button" class="ngPagerButton" ng-click="pageForward()" ng-disabled="cantPageForward()" title="__i18n.ngPagerNextTitle__"><div class="ngPagerLastTriangle ngPagerNextTriangle"></div></button>
// 最后一页
<button type="button" class="ngPagerButton" ng-click="pageToLast()" ng-disabled="cantPageToLast()" title="__i18n.ngPagerLastTitle__"><div class="ngPagerLastTriangle"><div class="ngPagerLastBar"></div></div></button>
</div>
</div>
showFooter
true: 显示或隐藏页脚,默认情况下页脚被禁用
rowHeight
36: 网格行高
headerRowHeight
36: 表头行高
enableRowSelection
false:行选择是否可用,默认为 true;
self.orig = fromCol;
self.width = fromCol.width;-------------------------# 表格宽度,int (42), string px('42px'),percentage string ('42%')
self.groupIndex = fromCol.groupIndex;
self.isGroupedBy = fromCol.isGroupedBy;
self.displayName = fromCol.displayName;-------------# 显示名称
self.index = fromCol.index;
self.isAggCol = fromCol.isAggCol;
self.cellClass = fromCol.cellClass;-----------------# 为列单元格追加 css 类
self.cellFilter = fromCol.cellFilter;
self.field = fromCol.field;-------------------------# 数据模型的属性
self.aggLabelFilter = fromCol.aggLabelFilter;
self.visible = fromCol.visible;
self.sortable = fromCol.sortable;
self.resizable = fromCol.resizable;-----------------# 列是否可调整大小
self.pinnable = fromCol.pinnable;-------------------# 是否可以将列固定到左侧
self.pinned = fromCol.pinned;
self.originalIndex = fromCol.originalIndex;
self.sortDirection = fromCol.sortDirection;
self.sortingAlgorithm = fromCol.sortingAlgorithm;
self.headerClass = fromCol.headerClass; ------------# 为列标题追加一个 css 类
self.headerCellTemplate = fromCol.headerCellTemplate;
self.cellTemplate = fromCol.cellTemplate;
self.cellEditTemplate = fromCol.cellEditTemplate;
demo
<div ng-class="row.entity[col.field] == 'success' ? 'successClass' : 'errorClass'">{{row.entity[col.field]}}</div>需要注意的是 ng-class="'successClass'" ,value 是需要有单引号的,切记
class 名加
''
如果需要控制的 class 名为多个单词,不加引号以 - 拼接会报错,小驼峰命名不会,但如果加引号,使用 - 拼接可小驼峰都没问题。
<span ng-class="{redColor: vm.status}">听风是风</span> ------- 正确
<span ng-class="{'red-color': vm.status}">听风是风</span>----- 正确(推荐)
<span ng-class="{red-color: vm.status}">听风是风</span>------- 错误
如下是 ng-class 常用的几种方式
ng-class 三元表达式
<div ng-class="row.entity[col.field] == 'success' ? 'successClass' : 'errorClass'">{{row.entity[col.field]}}</div>ng-class 对象写法
<select name="" id="" ng-model="vm.status">
<option value="color-blue">蓝色</option>
<option value="color-red">红色</option>
</select>
<span ng-class="{color-blue:'blue',color-red:'red'}[vm.status]">听风是风</span>ng-class 评估表达式
cellTemplate : '<span class="label" ng-class="{\'label-warning\' : row.entity.status == 1,\'label-info\':row.entity.status == 2,\'label-success\' : row.entity.status == 4,\'label-danger\' : row.entity.status == 5,\'label-primary\' : row.entity.status == 6,}">__html(row.entity.status)__ </span>',
页面首次加载时时正常,但是搜索条件改变后,未及时变化,修改为评估表达式后正常
cellTemplate : '<span class="label" ng-class="__mycolor(row.entity.status)__">__html(row.entity.status)__ </span>',
$scope.mycolor = function (stat) {
switch (stat) {
case '1':
return "\'label-warning\'";
break;
case '2':
return "\'label-info\'";
break;
case '4':
return "\'label-success\'";
break;
case '5':
return "\'label-danger\'";
break;
case '6':
return "\'label-primary\'";
break;
default:
return "\'label-default\'";
break;
}
}
width: __col.width__px
<button class="btn btn-success" style="width: __col.width__px" ng-click="open(row.entity.id)">详情</button>
cellTemplate:'<div class="ui-grid-cell-contents" > __row.entity.create_time | date:"yyyy-MM-dd hh:mm:ss"__</div>',
cellTemplate : '<span class="label" ng-class="{\'label-warning\' : row.entity.status == 1,\'label-info\':row.entity.status == 2,\'label-success\' : row.entity.status == 4,\'label-danger\' : row.entity.status == 5,\'label-primary\' : row.entity.status == 6,}">__grid.appScope.html(row.entity.status)__ </span>',
更新成 ui.grid 后,cellTemplate 使用变量函数时,需要加 grid.appScope.,如果方法和 grid 不在同一个 controller 中时,可以不加
以【wuxing】history 列表举例
state('app.wuxing.item_history_list', {
url: '/item_history_list?item_type&item_id&page_index',
templateUrl: 'static/tpl/wuxing/item_history_list.html',
resolve: load(['ui.grid', 'ui.grid.resizeColumns','ui.grid.pagination' ,'static/js/controllers/wuxing/item_history.js'])
})
var app = angular.module('app');
app.controller('WuxingItemHistoryListCtrl', ['$scope', '$modal', 'i18nService', 'Request', '$httpParamSerializer', '$stateParams', '$state',
function ($scope, $modal, i18nService, Request, $httpParamSerializer, $stateParams, $state) {
var getPagedDataAsync = function (curPage) {
setTimeout(function () {
var data;
var params = {};
params['item_type'] = $stateParams.item_type;
params['item_id'] = $stateParams.item_id;
if (curPage) {
params['page_index'] = curPage;
}
// update url, 添加下面一行 <===============================================
$state.go('.', params, {notify: false});
if ($scope.searchValue) {
params[$scope.selectedName] = $scope.searchValue;
}
params['page_size'] = 15;
Request.get('/wuxing/item_history_list?' + $httpParamSerializer(params),
function (res) {
if (res.data.list)
{
$scope.myData = res.data.list;
$scope.gridOptions.totalItems = res.data.total;
}
else
{
$scope.myData = [];
$scope.gridOptions.totalItems = 0;
}
}, false, true
);
},
100);
};
}]);
var app = angular.module('myApp', ['ui.grid', 'ui.grid.selection', 'ui.grid.edit', 'ui.grid.exporter', 'ui.grid.pagination', 'ui.grid.resizeColumns', 'ui.grid.autoResize']);
app.controller('MyCtrl',
function($scope, i18nService) {
// 国际化;
i18nService.setCurrentLang("zh-cn");
$scope.gridOptions = {
data: 'myData',
columnDefs: [{
field: 'name',
displayName: '名字',
width: '10%',
enableColumnMenu: false,
// 是否显示列头部菜单按钮
enableHiding: false,
suppressRemoveSort: true,
enableCellEdit: false // 是否可编辑
},
{
field: "age"
},
{
field: "birthday"
},
{
field: "salary"
}],
enableSorting: true,
// 是否排序
useExternalSorting: false,
// 是否使用自定义排序规则
enableGridMenu: true,
// 是否显示 grid 菜单
showGridFooter: true,
// 是否显示 grid footer,grid footer 为页脚的"总行数: 15" 而非分页按钮
enableHorizontalScrollbar: 1,
//grid 水平滚动条是否显示,0- 不显示 1- 显示(默认是 1)
enableVerticalScrollbar: 0,
//grid 垂直滚动条是否显示,0- 不显示 1- 显示(默认是 1)
//-------- 分页属性 ----------------
enablePagination: true,
// 是否分页,默认为 true,设置为 false 时,即使显示分页按钮也无效果
enablePaginationControls: true,
// 使用默认的底部分页,设置为 false 时,底部分页按钮消失
paginationPageSizes: [10, 15, 20],
// 每页显示个数可选项
paginationCurrentPage: 1,
// 当前页码
paginationPageSize: 10,
// 每页显示个数
//paginationTemplate:"<div></div>", // 自定义底部分页代码
totalItems: 0,
// 总数量
useExternalPagination: true,
// 是否使用分页按钮
//----------- 选中 ----------------------
enableFooterTotalSelected: true,
// 是否显示选中的总数,默认为 true, 如果显示,showGridFooter 必须为 true
enableFullRowSelection: true,
// 是否点击行任意位置后选中,默认为 false, 当为 true 时,checkbox 可以显示但是不可选中
enableRowHeaderSelection: true,
// 是否显示选中 checkbox 框 , 默认为 true
enableRowSelection: true,
// 行选择是否可用,默认为 true;
enableSelectAll: true,
// 选择所有 checkbox 是否可用,默认为 true;
enableSelectionBatchEvent: true,
// 默认 true
isRowSelectable: function(row) { //GridRow
if (row.entity.age > 45) {
row.grid.api.selection.selectRow(row.entity); // 选中行
}
},
modifierKeysToMultiSelect: false,
// 默认 false, 为 true 时只能 按 ctrl 或 shift 键进行多选,multiSelect 必须为 true;
multiSelect: true,
// 是否可以选择多个,默认为 true;
noUnselect: false,
// 默认 false, 选中后是否可以取消选中
selectionRowHeaderWidth: 30,
// 默认 30 ,设置选择列的宽度;
//-------------- 导出 ----------------------------------
exporterAllDataFn: function() {
return getPage(1, $scope.gridOptions.totalItems);
},
exporterCsvColumnSeparator: ',',
exporterCsvFilename: 'download.csv',
exporterFieldCallback: function(grid, row, col, value) {
if (value == 50) {
value = "可以退休";
}
return value;
},
exporterHeaderFilter: function(displayName) {
return 'col: ' + name;
},
exporterHeaderFilterUseName: true,
exporterMenuCsv: true,
exporterMenuLabel: "Export",
exporterMenuPdf: true,
exporterOlderExcelCompatibility: false,
exporterPdfCustomFormatter: function(docDefinition) {
docDefinition.styles.footerStyle = {
bold: true,
fontSize: 10
};
return docDefinition;
},
exporterPdfFooter: {
text: 'My footer',
style: 'footerStyle'
},
exporterPdfDefaultStyle: {
fontSize: 11,
font: 'simblack' //font 设置自定义字体
},
exporterPdfFilename: 'download.pdf',
/* exporterPdfFooter : {
columns: [
'Left part',
{ text: 'Right part', alignment: 'right' }
]
},
或 */
exporterPdfFooter: function(currentPage, pageCount) {
return currentPage.toString() + ' of ' + pageCount;
},
exporterPdfHeader: function(currentPage, pageCount) {
return currentPage.toString() + ' of ' + pageCount;
},
exporterPdfMaxGridWidth: 720,
exporterPdfOrientation: 'landscape',
// 'landscape' 或 'portrait' pdf 横向或纵向
exporterPdfPageSize: 'A4',
// 'A4' or 'LETTER'
exporterPdfTableHeaderStyle: {
bold: true,
fontSize: 12,
color: 'black'
},
exporterPdfTableLayout: null,
exporterPdfTableStyle: {
margin: [0, 5, 0, 15]
},
exporterSuppressColumns: ['buttons'],
exporterSuppressMenu: false,
//---------------api---------------------
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
// 分页按钮事件
gridApi.pagination.on.paginationChanged($scope,
function(newPage, pageSize) {
if (getPage) {
getPage(newPage, pageSize);
}
});
// 行选中事件
$scope.gridApi.selection.on.rowSelectionChanged($scope,
function(row, event) {
if (row) {
$scope.testRow = row.entity;
}
});
}
};
var getPage = function(curPage, pageSize) {
var firstRow = (curPage - 1) * pageSize;
$scope.gridOptions.totalItems = mydefalutData.length;
$scope.gridOptions.data = mydefalutData.slice(firstRow, firstRow + pageSize);
// 或者像下面这种写法
//$scope.myData = mydefalutData.slice(firstRow, firstRow + pageSize);
};
var mydefalutData = [{
name: "Moroni",
age: 50,
birthday: "Oct 28, 1970",
salary: "60,000"
},
{
name: "Tiancum",
age: 43,
birthday: "Feb 12, 1985",
salary: "70,000"
},
{
name: "Jacob",
age: 27,
birthday: "Aug 23, 1983",
salary: "50,000"
},
{
name: "Nephi",
age: 29,
birthday: "May 31, 2010",
salary: "40,000"
},
{
name: "Enos",
age: 34,
birthday: "Aug 3, 2008",
salary: "30,000"
},
{
name: "Moroni",
age: 50,
birthday: "Oct 28, 1970",
salary: "60,000"
},
{
name: "Tiancum",
age: 43,
birthday: "Feb 12, 1985",
salary: "70,000"
},
{
name: "Jacob",
age: 27,
birthday: "Aug 23, 1983",
salary: "40,000"
},
{
name: "Nephi",
age: 29,
birthday: "May 31, 2010",
salary: "50,000"
},
{
name: "Enos",
age: 34,
birthday: "Aug 3, 2008",
salary: "30,000"
},
{
name: "Moroni",
age: 50,
birthday: "Oct 28, 1970",
salary: "60,000"
},
{
name: "Tiancum",
age: 43,
birthday: "Feb 12, 1985",
salary: "70,000"
},
{
name: "Jacob",
age: 27,
birthday: "Aug 23, 1983",
salary: "40,000"
},
{
name: "Nephi",
age: 29,
birthday: "May 31, 2010",
salary: "50,000"
},
{
name: "Enos",
age: 34,
birthday: "Aug 3, 2008",
salary: "30,000"
}];
getPage(1, $scope.gridOptions.paginationPageSize);
});
需要使用 grid.appScope.
$scope.gridScope = $scope;
$scope.gridOptions = {
columnDefs = [
{ name: 'edit', displayName: 'Edit', cellTemplate: '<button ng-click="grid.appScope.edit(row.entity)" >Edit</button>' }
],
data: myData
};
$scope.edit = function( entity ) {
...some custom function using entity...
};