当前位置: 代码迷 >> JavaScript >> 利用jquery依据json文本动态的生成可分组的table,并实现checkbox partial check功能
  详细解决方案

利用jquery依据json文本动态的生成可分组的table,并实现checkbox partial check功能

热度:413   发布时间:2013-09-29 11:07:08.0
利用jquery根据json文本动态的生成可分组的table,并实现checkbox partial check功能

? 近来根据项目需求,需要实现动态的根据json文本生成一个可分组的table功能,并且需要实现类似tree的展开和收缩功能, 另外附带checkboxpartial check功能。

? 查阅了不少js framework,没有比较顺手的,都需要二次开发,于是打算自己写一个简单的, 先看一个页面:



?Basic Framework: Jquery, 因为需要很多的selector操作,而jquery的$()不是盖的,而且只需要用到jquery的min js,比较轻量级。

Partial Checkbox 的实现,因为checkbox本身不支持partial check, 所以需要用图片来实现,基本原理是底层一个白色的空图片,根据点击事件来动态的更换background picture。

Json parser: 我实现的很简单,json文本中放置一个数组,里面是需要显示的对象, 利用jquery的each方法遍历文本,分析出group和group item, 调用jquery的append方法生成tr

json 文本如下:

?

var data = 
{"source":
[
	{
		"groupName":100001,
	    "setpointTemplateId":2212,
		"protocolName":"ComTrol 6k",
		"unifiedAppTypeName":"Suction Group",
		"unifiedPointName":"SUCT PRES SETPT",
		"energyCritical":true,
		"alarmSetpoint":false,
		"checkOveride":false,
		"isChecked":true,
		"checkWaringMsg":"function(isChecked){if(isChecked){alert('If you unchecked this point, you can not calculate the benefit.');}}"
	},
	{
		"groupName":100001,
	    "setpointTemplateId":2213,
		"protocolName":"ComTrol 6k",
		"unifiedAppTypeName":"Suction Group",
		"unifiedPointName":"Lead Float Ckt",
		"energyCritical":false,
		"alarmSetpoint":true,
		"checkOveride":false,
		"isChecked":false,
		"checkWaringMsg":''
	},
	{
		"groupName":100001,
	    "setpointTemplateId":2214,
		"protocolName":"ComTrol 6k",
		"unifiedAppTypeName":"Suction Group",
		"unifiedPointName":"FLOAT TEMP",
		"energyCritical":true,
		"alarmSetpoint":false,
		"checkOveride":false,
		"isChecked":false,
		"checkWaringMsg":''
	},
	{
		"groupName":100002,
	    "setpointTemplateId":1000,
		"protocolName":"E2",
		"unifiedAppTypeName":"Suction Group",
		"unifiedPointName":"CONTROL TEMP",
		"energyCritical":false,
		"alarmSetpoint":true,
		"checkOveride":false,
		"isChecked":false,
		"checkWaringMsg":''
	},
	{
		"groupName":100002,
	    "setpointTemplateId":1001,
		"protocolName":"E2",
		"unifiedAppTypeName":"Suction Group",
		"unifiedPointName":"FLOAT TEMP",
		"energyCritical":true,
		"alarmSetpoint":false,
		"checkOveride":false,
		"isChecked":false,
		"checkWaringMsg":''
	},
	{
		"groupName":100002,
	    "setpointTemplateId":1002,
		"protocolName":"E2",
		"unifiedAppTypeName":"Suction Group",
		"unifiedPointName":"FLOAT TEMP",
		"energyCritical":false,
		"alarmSetpoint":true,
		"checkOveride":false,
		"isChecked":false,
		"checkWaringMsg":''
	}
]
};

?html页面:

?

?

<!DOCTYPE html>
<html>
<head>
  <script type="text/javascript" src="data.js"></script>
  <script type="text/javascript" src="jquery.js"></script>
  <script type="text/javascript" src="index_1.js"></script>
  <style type="text/css">
	.node-unchecked {background-image: url(unchecked.gif);}
	.node-checked-partial {background-image: url(checked-partial.gif);}
	.node-checked {background-image: url(checked.gif);}
	.image-checkbox {border: 0 none;height: 18px;margin: 0;padding: 0;vertical-align: middle;width: 15px;background-repeat: no-repeat;}
	#custom_profile_table
	{
		border-collapse:collapse;
	}
	#custom_profile_table td, #custom_profile_table th 
	{
		border:1px solid #ADADAA;
		padding:3px 3px 3px 3px;
		text-align:center;
	}
	#custom_profile_table th 
	{
		text-align:center;
		padding-top:5px;
	}
	#custom_profile_table tr.alt td 
	{
		color:#000;
		background-color:#EAF2D3;
	}

  </style>
</head>
<body>
<table>
	<tr>
		<td><button onClick="selectHelperHandler('SELECT_ALL_ENERGY')">Select all Energy Critical Setpoint</button></td>
		<td><button onClick="selectHelperHandler('SELECT_ALL_ALARM')">Select all Alarm Setpoint</button></td>
		<td><button onClick="selectHelperHandler('SELECT_ALL')">Select all</button></td>
		<td><button onClick="selectHelperHandler('UNSELECT_ALL')">Un Select All</button></td>
	</tr>
</table>
<br>
<table id="custom_profile_table">
	<thead>
		<tr>
			<th colspan="2"></th>
			<th>Application Type</th>
			<th>Protocol</th>
			<th>Point</th>
			<th>Recommend Energy Critical</th>
			<th>Recommend Alarm Critical</th>
			<th>Check Override</th>
		</tr>
	</thead>
	<tbody>
		
	</tbody>
</table>
</body>
</html>

?javascript如下

?

?

var MAIN_TABLE_ID = "custom_profile_table";
var PLUG_MIN_IMG_ID = "plus-min";

var CHECKBOX_UNCHECKED = 'node-unchecked';
var CHECKBOX_CHECKED = 'node-checked';
var CHECKBOX_PARTIAL = 'node-checked-partial';

//id prefix for the tr tag
var PARENT = 'parent_';
var CHILD = 'child_';
//id prefix for the checkbox img tag
var ALL = "all_";
var SUB = "sub_";

//unique id
var PARENT_UNIQUE_TEMPLATE_ID = '00000';

//the plus and minus picture define
var PLUS_SRC = "plusnolines.gif";
var MINUS_SRC = "minusnolines.gif";

var YES = "yes";
var NO = "no";

var SELECT_ALL_ENERGY = "SELECT_ALL_ENERGY";
var SELECT_ALL_ALARM = "SELECT_ALL_ALARM";
var SELECT_ALL = "SELECT_ALL";
var UNSELECT_ALL = "UNSELECT_ALL";
/**********************************************
	Select all handler for checkbox image
**********************************************/
function selectAll(all)
{
	var selectedAllImg = $('#' + all.id);
	var bUnchecked = selectedAllImg.hasClass(CHECKBOX_UNCHECKED);
	var bPartialChecked = selectedAllImg.hasClass(CHECKBOX_PARTIAL);
	var bChecked = selectedAllImg.hasClass(CHECKBOX_CHECKED);
	if(bUnchecked)
	{
		selectedAllImg.removeClass(CHECKBOX_UNCHECKED);
		selectedAllImg.addClass(CHECKBOX_CHECKED);
	}
	else
	{
		selectedAllImg.removeClass(CHECKBOX_CHECKED);
		selectedAllImg.removeClass(CHECKBOX_PARTIAL);
		selectedAllImg.addClass(CHECKBOX_UNCHECKED);
	}
	
	var groupName = extractGroupName(selectedAllImg);
	$('table#' + MAIN_TABLE_ID + ' img[id^=sub_'+groupName+']').each(function()
		{
			var hiddenId = $(this).attr('id').replace("sub","hidden");
			if(bUnchecked)
			{
				$(this).removeClass(CHECKBOX_UNCHECKED);
				$(this).addClass(CHECKBOX_CHECKED);
				$('table#' + MAIN_TABLE_ID + ' input[id='+hiddenId+']').attr('checked', true);
			}
			else
			{
				$(this).removeClass(CHECKBOX_CHECKED);
				$(this).removeClass(CHECKBOX_PARTIAL);
				$(this).addClass(CHECKBOX_UNCHECKED);
				$('table#' + MAIN_TABLE_ID + ' input[id='+hiddenId+']').attr('checked', false);
			}
		}
	)		
}

/**********************************************
	Select all handler for checkbox image
**********************************************/
function selectSub(sub)
{
	selectSubById(sub.id);	
	scanForAllCheckCss(extractGroupName($('#' + sub.id)));
}

function selectSubById(id, forceValue)
{
	var selectedSubImg = $('#' + id);
	var bUnchecked = selectedSubImg.hasClass(CHECKBOX_UNCHECKED);
	var bChecked = selectedSubImg.hasClass(CHECKBOX_CHECKED);
	
	var groupName = extractGroupName(selectedSubImg);
	
	var hiddenId = id.replace("sub","hidden");
	if(bUnchecked || forceValue)
	{
		selectedSubImg.removeClass(CHECKBOX_UNCHECKED);
		selectedSubImg.addClass(CHECKBOX_CHECKED);
		$('table#' + MAIN_TABLE_ID + ' input[id='+hiddenId+']').attr('checked', true);
	}
	else
	{
		selectedSubImg.removeClass(CHECKBOX_CHECKED);
		selectedSubImg.addClass(CHECKBOX_UNCHECKED);
		$('table#' + MAIN_TABLE_ID + ' input[id='+hiddenId+']').attr('checked', false);
	}
}

function scanForAllCheckCss(groupName)
{
	var allImg = $('table#' + MAIN_TABLE_ID + ' img[id=all_'+groupName+'_'+PARENT_UNIQUE_TEMPLATE_ID+']');
	allImg.removeClass(CHECKBOX_UNCHECKED);
	allImg.removeClass(CHECKBOX_CHECKED);
	allImg.removeClass(CHECKBOX_PARTIAL);
	
	var bFoundChecked=false;
	var bFoundUnchecked=false;
	
	$('table#' + MAIN_TABLE_ID + ' img[id^=sub_'+groupName+']').each(function()
		{
			if($(this).hasClass(CHECKBOX_CHECKED))
			{
				bFoundChecked=true;
			}
			else
			{
				bFoundUnchecked=true;
			}
			
			if(bFoundChecked && bFoundUnchecked)
			{
				allImg.addClass(CHECKBOX_PARTIAL);
				return false;
			}
		}
	)
	
	if(bFoundChecked && !bFoundUnchecked)
	{
		allImg.addClass(CHECKBOX_CHECKED);
	}
	if(bFoundUnchecked && !bFoundChecked)
	{
		allImg.addClass(CHECKBOX_UNCHECKED);
	}

}
	
/**********************************************
	extract the group name
**********************************************/
function extractGroupName(jqueryObject)
{
	var items = jqueryObject.attr('id').split('_');
	return items[1];
}

var cachedGroupName = new Array();
var tbody;
function buildTableBody()
{
	$(data.source).each(function(index, element){
		if(cachedGroupName.indexOf(element.groupName)==-1)
		{
			cachedGroupName[cachedGroupName.length]=element.groupName;
			addParentTr(element);
		}
		addChildTr(element);      
    })
}

function addParentTr(element)
{
	var buffer = ''
	.concat('<tr id="parent_' + element.groupName+ '_' + PARENT_UNIQUE_TEMPLATE_ID + '">')
	.concat('<td><img src="' + MINUS_SRC + '" id="plus-min_' + element.groupName + '_' + PARENT_UNIQUE_TEMPLATE_ID + '"/><img src="s.gif" class="image-checkbox node-unchecked" onClick="selectAll(this)" id="all_' +  + element.groupName + '_' + PARENT_UNIQUE_TEMPLATE_ID + '"/></td>')
	.concat('<td>&nbsp;</td>')
	.concat('<td>' + element.unifiedAppTypeName + '</td>')
	.concat('<td>' + element.protocolName + '</td>')
	.concat('<td>--</td>')
	.concat('<td>--</td>')
	.concat('<td>--</td>')
	.concat('<td>--</td>')
	.concat('</tr>'); 
	
	tbody.append(buffer);
}
var checkboxIndex;
function addChildTr(element)
{
	var checkCss = CHECKBOX_UNCHECKED;
	var checkStr = '';
	var checkFuc = 'null';
	if(element.checkWaringMsg != null
		&&element.checkWaringMsg.trim()!='')
	{
		checkFuc = element.checkWaringMsg;
	}
	if(element.isChecked)
	{
		checkCss = CHECKBOX_CHECKED;
		checkStr = 'checked';
	}
	
	var buffer = ''
	.concat('<tr id="child_' + element.groupName + '_' + element.setpointTemplateId + '">')
	.concat('<td>&nbsp;</td>')
	.concat('<td><img src="s.gif" class="image-checkbox ' + checkCss + '" onClick="commonCheck(this,' + checkFuc + '),selectSub(this)" id="sub_'+element.groupName+'_'+element.setpointTemplateId+'"/><input style="display:none" type="checkbox" name="selectedTemplate[' +  checkboxIndex + ']" value="' + element.groupName + '" ' + checkStr + ' id="hidden_'+element.groupName+'_'+element.setpointTemplateId+'"/></td>')
	.concat('<td>--</td>')
	.concat('<td>--</td>')
	.concat('<td>' + element.unifiedPointName + '</td>')
	.concat('<td>' + (element.energyCritical?YES:NO) + '</td>')
	.concat('<td>' + (element.alarmSetpoint?YES:NO) + '</td>')
	.concat('<td>' + (element.checkOveride?YES:NO) + '</td>')
	.concat('</tr>');
	
	tbody.append(buffer);
	
	checkboxIndex++;
}

function commonCheck(node, str)
{
	if(str == null) 
		return;
	var isChecked = $('#' + node.id).hasClass('node-checked');
	eval("var func = " + str);
	func(isChecked);
}

function selectHelperHandler(condition)
{
	$(data.source).each(function(index, element){
	
		switch(condition)
		{
			case SELECT_ALL_ENERGY:
				if(element.energyCritical)
				{
					selectSubById('sub_' + element.groupName + '_' + element.setpointTemplateId, true);
				}
				break;
			case SELECT_ALL_ALARM:
				if(element.alarmSetpoint)
				{
					selectSubById('sub_' + element.groupName + '_' + element.setpointTemplateId, true);
				}
				break;
			case SELECT_ALL:
				selectSubById('sub_' + element.groupName + '_' + element.setpointTemplateId, true);
				break;
			case UNSELECT_ALL:
				selectSubById('sub_' + element.groupName + '_' + element.setpointTemplateId, false);
				break;
		}
    });
	
	$(cachedGroupName).each(function(index, element)
	{
		scanForAllCheckCss(element);
	});
}

$(function(){
	checkboxIndex = 0;
	tbody = $('table#' + MAIN_TABLE_ID + ' tbody');
	buildTableBody();
	$(cachedGroupName).each(function(index, element)
	{
		scanForAllCheckCss(element);
	}
	);
	
	$('table#' + MAIN_TABLE_ID + ' tr td img[id^=' + PLUG_MIN_IMG_ID + ']')
			.click(function(){
				if($(this).attr("src") == PLUS_SRC)
				{
					$(this).attr('src', MINUS_SRC);
				}
				else
				{
					$(this).attr('src', PLUS_SRC);
				}
				var parentTr = $(this).parent().parent();
				var groupName = extractGroupName(parentTr);
				//parentTr.siblings('#child_'+ groupName).toggle();
				$('table#' + MAIN_TABLE_ID + ' tr[id^=child_'+groupName+']').toggle();
			});
	$('table#' + MAIN_TABLE_ID + ' tr[id^=child_]').hide();
})

?

?

总结: 里面最重要的jquery的selector的使用,包括模糊匹配, 另外就是jquery的遍历和动态的操作tag的可见性和样式,?scanForAllCheckCss()用来在页面初始和item点击的时候调用,用来确定是否是partial check,selectHelperHandler()用来实现全选,全取消和条件选择。

?

完整代码见附件, 可以访问index_1.html看效果。

  相关解决方案