背景:
使用treegrid,实现一个树形的职业选择(多选)。
需求:
1)选中一个最低级的节点,能够自动选中所有父节点。
2)取消选中某节点下唯一的选中节点,则取消的父节点也一并取消,并且用该规则迭代被取消节点的所有父节点。
3)勾选一个父节点,则子节点全选,同理,反选父节点,子节点也反选。
设计及实践:
一、页面部分
页面部分没有什么东西,这里去掉了一个<th data-options="field:'ck',checkbox=true"></th>因为这个东西会被测试提bug。(后叙)
<table id="occupationGrid" class="easyui-treegrid" style="width:656px;height:426px;">
<thead>
<tr>
<th data-options="field:'professionId',hidden:true">主键</th>
<th data-options="field:'customerId',hidden:true">保险公司主键</th>
<th data-options="field:'name',align:'left'">行业名称</th>
<th data-options="field:'code',align:'left'">行业代码</th>
<th data-options="field:'type',align:'center'">行业类别</th>
</tr>
</thead>
</table>
二、JavaScript部分
$('#occupationGrid').treegrid({
url:'profession/query.action?customerId='+customerId+'&active=1',
idField:'professionId',
treeField:'name',
singleSelect:false,
rownumbers:true,
loadMsg:'正在载入数据',
onClickRow:function(row){
//获取所有选中节点并遍历他们
var select = $('#occupationGrid').treegrid('getSelections');
for(var i=0;i<select.length;i++)
{
if(select[i].professionId==row.professionId)
{
// ①选中某个节点,遍历所有父节点,设置选中
if(row.parentId && row.parentId!=0)
{
parentOption('select',row.parentId);
}
// ②同步处理该节点下的子节点
var children = row.children;
if(children && children.length>0)
{
childOperation('select',children)
}
return;
}
}
//取消选中行的子节点
var children = row.children;
if(children && children.length>0)
{
childOperation('unselect',children);
}
unselectParents(row);
/**
* 设置子节点选中/取消选中
* @param method 选:'select'/不选'unselect'
* @param children 子节点的数据
*/
function childOperation(method,children)
{
for(var i=0;i<children.length;i++)
{
var thisRow = children[i];
$('#occupationGrid').treegrid(method,thisRow.professionId);
if(children[i].children && children[i].children.length>0)
{
childOperation(method,children[i].children);
}
}
}
/**
* 处理所有父节点选中或取消选中
* @param method 选:'select'/不选'unselect'
* @param parentId 父节点id
*/
function parentOption(method,parentId)
{
if(!parentId)
{
return;
}
$('#occupationGrid').treegrid(method,parentId);
var thisNode = $('#occupationGrid').treegrid('find',parentId);
if(thisNode.parentId && thisNode.parentId!=0)
{
parentOption(method,thisNode.parentId);
}
}
/**
* 取消选中节点的父节点
* 必须是当前节点的兄弟节点都没有选中的情况下,才去取消父节点,要逐级判断
* @param row
*/
function unselectParents(row){
//判断该行同级节点是否有选中,若都没有,则取消该节点上级选中
if(row.parentId && row.parentId!=0)
{
var noCheckChildren = false;
var parentNode = $('#occupationGrid').treegrid('find',row.parentId);
var childrenNodes =
$('#occupationGrid').treegrid('getChildren',row.parentId);
for(var i=0;i<childrenNodes.length;i++)
{
var a = $('tr[node-id='+childrenNodes[i].professionId+']')
.hasClass('datagrid-row-checked datagrid-row-selected');
if(a)
{
noCheckChildren = true;
}
}
if(!noCheckChildren)
{
$('#occupationGrid').treegrid('unselect',parentNode.professionId);
unselectParents(parentNode);
}
}
}
},
onLoadSuccess:function(row, data){
professionIds = $('#occupationGrid').treegrid('getSelections');
}
});
1)通过onSelect/unSelect事件,只能实现需求三,当选中一个父节点会同时触发多个需求。因为使用了以下方法来实现选中/不选:
$('#id').treegrid('select',row.id);//这个方法本身会触发onSelect事件,所以会出现冲突,不能用。
2)找遍了api文档,想尽了办法得到上面的代码。但是由于checkbox的存在,这个独立于数据区的选项,并不遵循绑定的事件触发,于是只能将checkbox删除,免得测试提bug。