使用Angularjs在带来方便的同时,也有一些遗憾:很多基于jquery或其它的组件,在angularjs中需要集成一下才能用得流畅。但是一些比较复杂的组件,集成起来的工作量相当大,比如说grid。
大多数情况下,使用angularjs可以方便地实现简单的表格,甚至点击修改这样的功能也很容易。但是如果还希望增加更多的功能,比如拖动改变列的前后顺序,点击表头排序,拖动列宽度,隐藏某些列时,就不那么容易了。如果还想加上分组的功能,那就十分麻烦了。这时候我们就需要一个与angularjs配合很好的grid组件。
这几天我试用了http://angular-ui.github.com/ng-grid/,它完全是基于angularjs写的,所以可以使用angularjs的思路与它交互。使用感觉还不错,基本功能齐全,与之交互实现需要的效果也很顺畅。我用它简单地实现了一个表格设计器,在这里演示一下。
我实现的功能如下:
因为该项目的文档和示例写得比较好,而且当前还在紧张改进之中,所以我在这里不详细介绍如何使用,主要来演示效果。想使用的朋友可以上项目主页看,有问题在issues里提,作者回复很快很热心。
上面的按钮是我自己加的,下面的表格是由ng-grid提供的。可以看到它的外观跟普通的grid差不多,可单选(或多选),可调整宽度及列顺序,点击表头可排序,右上角有个小三角还有一些高级功能:
可在这里搜索(针对所有列),可以显示或者隐藏某列,右边那些小图标点击后会分组:
在上面有一个“配置表格”的按钮,点击后将会出现设计器窗口:
这是一个简单的设计器,它主要用来添加、删除列,改列头,以及调整顺序。左下角是当前已经使用的列,左边是field,对于json数据中某个key,右边是显示在列头的自定义名称;点击每行右边的[-]后,将删除该列;点击左下角的[+],将会新增一列。
左上角显示的是数据源中的json数据里存在但未被使用的key。点击旁边的[+]后,它就会移到下方。从下方删除后,就会回到上方。
右边是表格预览,我们可以调整列宽以及前后顺序。
可以看出这里调整的都是一些比较基本但又重要的参数,更详细的设置(比如为某列单元格自定义显示模板,配置列排序函数等),还得手动写代码实现。
当调整完成后,下方还有一个“保存”按钮(没在截图上显示),点击后,就会把当前的配置提交到服务器保存起来供使用。
代码写得比较粗糙,因为只是为了检验是否能满足需求,还未细化,仅供参考。
在js中定义:
// http://angular-ui.github.com/ng-grid/#/api
admin.directive('configureGrid', [ 'JsRoutes', function (JsRoutes) {
return {
restrict: "A",
controller: function ($scope, $element, $attrs, $transclude) {
var params = $scope.$parent.$eval($attrs["configureGrid"]);
$scope.gridId = params.id;
var dataName = params.dataName;
JsRoutes.Directives.getGridOptions.get({
id: $scope.gridId
}, function (options) {
if (options && options.columns) {
$scope.columnDefs = options.columns;
}
})
$scope.gridColumns = [];
$scope.configureGridModalShown = false;
$scope.$parent.configureGrid = function () {
$scope.configureGridModalShown = true;
}
$scope.$watch('gridWidth', function (newV) {
$scope.layoutPlugin1.updateGridLayout();
});
$scope.layoutPlugin1 = new ngGridLayoutPlugin();
$scope.columnDefs = [ ];
$scope.gridOptions = {
data: dataName,
columnDefs: 'columnDefs',
plugins: [$scope.layoutPlugin1]
}
$scope.$on('ngGridEventColumns', function (newColumns) {
var columns = newColumns.targetScope.columns;
columns = columns.filter(function (col) {
return col.field !== '✔';
})
$scope.gridColumns = columns.map(function (col) {
return {
field: col.field,
displayName: col.displayName,
width: col.width
}
});
var total = 0;
$scope.gridColumns.forEach(function (col) {
total += col.width;
});
$scope.gridWidth = total;
});
$scope.gridWidth = 500;
$scope.$on('')
$scope.getFields = function () {
var data = $scope.$parent[dataName];
if (data && data.length > 0) {
var keys = _.keys(data[0]);
return _.reject(keys, function (key) {
return _.find($scope.columnDefs, function (col) {
return col.field === key;
});
});
}
return [];
}
$scope.addColumn = function (field) {
$scope.columnDefs.push({
field: field,
displayName: field,
width: 100
});
}
$scope.removeColumn = function (col) {
$scope.columnDefs = _.reject($scope.columnDefs, function (c) {
return c.field == col.field;
});
}
$scope.$watch(dataName, function (data) {
if (data.length > 0 && $scope.columnDefs.length == 0) {
$scope.getFields().forEach(function (f) {
$scope.addColumn(f);
});
}
})
$scope.saveGridOptions = function () {
JsRoutes.Directives.saveGridOptions.post({
id: $scope.gridId,
columns: $scope.gridColumns
}, function () {
$scope.configureGridModalShown = false;
}, null, {
postType: 'json'
});
}
},
scope: true,
templateUrl: JsRoutes.Directives.configureGrid.link({format: 'html'})
}
}])
对应的html代码:
<div id="configure-modal">
<style type="text/css">
#configure-modal .modal {
position: fixed;
margin-left: -45%;
margin-top: 30px;
width: 90%;
} #configure-modal .modal-body {
max-height: none;
} #configure-modal .fade.in {
top: 30px;
} </style>
<div ui-modal class="fade configure-modal" ng-model="configureGridModalShown">
#{debug /}
<div class="modal-header"><h3>定制表格 [{{gridId}}]</h3></div>
<div class="modal-body">
<table class="table-as-layout">
<tr>
<td ui-fixed-width="300">
<ul>
<li ng-repeat="field in getFields()">{{field}}
<a ng-click="addColumn(field)">[+]</a>
</li>
</ul>
<hr/>
<ul>
<li ng-repeat="col in columnDefs">
<div>
<span ng-click="details=!details" style="cursor: pointer">
<input type="text" class="input input-small" ng-model="col.field" ng-model-onblur/>
- <input type="text" class="input input-small" ng-model="col.displayName" ng-model-onblur/>
</span>
<a ng-click="removeColumn(col)">[-]</a>
</div>
</li>
<li><a ng-click="addColumn('todo')">[+]</a></li>
</ul>
</td>
<td width="100%">
<div class="gridStyle" style="width:{{gridWidth}}px;height:600px" ng-grid="gridOptions"></div>
</td>
</tr>
</table>
</div>
<div class="modal-footer">
<a class="btn btn-primary" data-dismiss="modal" ng-click="saveGridOptions()">保存</a>
<a class="btn" data-dismiss="modal">关闭</a>
</div>
</div>
</div>
调用该设计器的代码:
<button class="btn" ng-click="configureGrid()">
<i class="icon-table"> </i> 配置表格
</button>
<div configure-grid="{id:gridId, dataName: gridDataName}">
</div><script type="text/javascript">
function Ctrl($scope, JsRoutes, Commons) {
$scope.users = [];
$scope.gridId = '402880843CAE4701013CAE594B390001';
$scope.gridDataName = 'users';
$scope.columnDefs = [];
$scope.gridOptions = {
data: $scope.gridDataName,
columnDefs: 'columnDefs',
beforeSelectionChange: function (event) {
event.entity.checked = !event.selected;
return true;
}
}
}
</script>
在页面中使用保存的参数显示表格
Html代码:
<div ng-grid="gridOptions" style="width: 100%;height: 500px"></div>
Js代码:
$scope.users = [];
$scope.gridId = '402880843CAE4701013CAE594B390001';
$scope.gridDataName = 'users';
$scope.columnDefs = [];
$scope.gridOptions = {
data: $scope.gridDataName,
columnDefs: 'columnDefs',
beforeSelectionChange: function (event) {
event.entity.checked = !event.selected;
return true;
}
}
JsRoutes.Directives.getGridOptions.get({
id: $scope.gridId
}, function (options) {
console.log(options);
if (options && options.columns) {
$scope.columnDefs = options.columns;
}
})
注意,以上代码仅供参考思路,里面缺了东西,不能直接运行。另外,ng-grid的代码改得比较快,请注意它的最新文档。