如何使用jQuery UI的sortable组件做一个更为友好的界面(下)

85 篇文章 0 订阅
58 篇文章 0 订阅

Realize the One-way, One-to-multiple, Drag&Drop Lists


Set up Basic Program


This time, no sortable involved; but the program got more complex, since we need more functionalities. We will use Draggable and Droppable instead. The behaviors would be:


1. when dragging an item, one copy would be dragged, not the original instance;

2. where will be more than one containers receive the draggables, namely multiple droppables;

3. after the item be dropped into the target containers, it would have one remove button;

4. one droppable only receive one sole copy of item, if another one is dropped on that already has one, the preceding one would be removed automatically;


Okay, let's do it:


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 

<head>

	<meta charset="utf-8">

	<title>Editing Scheduler - Day List</title>

	<link rel="stylesheet" href="script/css/custom-theme/jquery-ui-1.8.18.custom.css">

	<script src="script/js/jquery-1.6.2.min.js"></script>

	<script src="script/js/jquery-ui-1.8.21.custom.min.js"></script>

	<style type="text/css">

		#day-list-container {

			width: 360px; 
			height: 780px; 
			border: 1px solid crimson; 
			float: right;

		}

		#day-list {

			padding-left: 4px;

		}

		.day-list-item {

			width: 200px; 
			height: 26px; 
			border: 1px solid #DDD;
			background-color: #FBFBFB;
			background-image: url('images/day-icon--background.png');
			background-repeat: no-repeat;
			background-position: top left;
			margin-top: 5px;
			padding: 4px;
			list-style-type: none;
			position: relative;

		}

		.day-list-item label {

			margin-left: 26px;
			font-size: 0.8em;

		}

		.day-list-item .remove {   

            width: 26px;
            height: 26px; 
            background-image: url('images/red-cross.png');  
			position: absolute;
			top: 4px;
			right: 10px;

        }

		#week-scheduler {

			width: 840px; 
			height: 480px; 
			border: 1px solid mediumvioletred; 
			float: left;

		}

		.day-of-week {

			width: 228px; 
			height: 80px; 
			border: 1px solid greenyellow; 
			float: left;
			position: relative;

		}

		.day-container {

			width: 220px; 
			height: 60px; 
			border: 2px solid hotpink; 
			padding-left: 0px;
			margin-top: 0px;
			margin-bottom: 0px;
			position: absolute;
			bottom: 0px;
			right: 0px;

		}

	</style>

</head>

<body>

	<div id="day-list-container">

		<label id="title">days</label>

		<ul id="day-list"> 

			<li id="day_1" class="day-list-item"><label>how could a</label></li> 
			<li id="day_2" class="day-list-item"><label>day-02</label></li> 
			<li id="day_3" class="day-list-item"><label>day-03</label></li> 
			<li id="day_4" class="day-list-item"><label>day-04</label></li> 

		</ul>

	</div>



	<form action="" method="post" id="form-schdl-day">

		<div id="week-scheduler">

			<div id="monday" class="day-of-week">

				<ul id="schd-monday" class="day-container"></ul>

			</div>

			<div id="tuesday" class="day-of-week">

				<ul id="schd-tuesday" class="day-container"></ul>

			</div>

			<div id="wedonsday" class="day-of-week">

				<ul id="schd-wedonsday" class="day-container"></ul>

			</div>

			<div id="thursday" class="day-of-week">

				<ul id="schd-thursday" class="day-container"></ul>

			</div>

		</div>

		<input type="submit" value="submit"/>

	</form>

	<script type="text/javascript"> 

		$(function() {

			$( "#day-list li" ).draggable({

				connectToSortable: ".day-container",

				helper: "clone",

				revert: "invalid"

			});

			$( ".day-container" ).droppable({

				drop: function( event, ui ) {

					var $cur_id = ui.draggable.attr("id");

					var $li = $( "<li class=\"day-list-item\"></li>" ).attr("id", $cur_id).appendTo( this );

					$( "<label></label>" ).text( ui.draggable.text() ).appendTo( $li );

					$( "<div class=\"remove\"></div>" ).appendTo( $li );

					
					
					var $num = $(this).find("li").size();

					if($num > 1)

					{

						var $first_li = $(this).find("li").first();

						//$first_li.hide( 500, function(){ $(this).remove();} );	// no idea why it not work

						$first_li.hide( 

										250, 

										function()

										{

											$(this).remove();

										} 

									);

					}

				}

			});		

			$(".day-list-item .remove").live(

										'click', 

										function() 

										{
											$(this).closest('.day-list-item').remove();

										}

									);

			$( "ul, li" ).disableSelection();
			

		});

	</script>

</body> 

</html>


It is ugly, but just fine for the stage:


one-way-design


Some Necessary Explanation


Because we want the UL tag of the weekday stay at the right bottom of their containers, we set their CSS position to 'absolute', and their parent tag position to 'relative'.


By default, if you indicate that jQuery handle dragging by duplicating one copy, then there is nothing happen when you drop it, so you need to code that on your own, and what we do is to create the same HTML piece and insert it into the target container, but we do more, we insert a remove button:


var $li = $( "<li class=\"day-list-item\"></li>" ).attr("id", $cur_id).appendTo( this );

$( "<label></label>" ).text( ui.draggable.text() ).appendTo( $li );

$( "<div class=\"remove\"></div>" ).appendTo( $li );

And we also need to bind the click event handler to the remove button, but we have to use live().


Pass the Data to Server


And this is our final purpose. But this time it is different, since we have multiple receiving containers. Adding one single hidden input won't work well. We add one hidden input to each container!!!


<div id="week-scheduler">

	<div id="monday" class="day-of-week">

		<ul id="schd-monday" class="day-container"></ul>

		<input type="hidden" name="schdl-day[]" id="monday-schdl-day" value="">

	</div>

	<div id="tuesday" class="day-of-week">

		<ul id="schd-tuesday" class="day-container"></ul>

		<input type="hidden" name="schdl-day[]" id="tuesday-schdl-day" value="">

	</div>

	<div id="wedonsday" class="day-of-week">

		<ul id="schd-wedonsday" class="day-container"></ul>

		<input type="hidden" name="schdl-day[]" id="wedonsday-schdl-day" value="">

	</div>

	<div id="thursday" class="day-of-week">

		<ul id="schd-thursday" class="day-container"></ul>

		<input type="hidden" name="schdl-day[]" id="thursday-schdl-day" value="">

	</div>

</div>


Because each container only have one element, which is day item, then we can use an array to ship them, so we name the hidden input with the same name 'schdl-day'.


And then, we use javascript to operate this hidden input when adding or removing items. Add this block to drop handler of the Droppable:

var $ip = $(this).next("input").first();

$ip.val($cur_id);

Add the lines to bind the click event of remove button:

$(".day-list-item .remove").live(

							'click', 

							function() 

							{

								var $cont = $(this).closest('.day-container');

								$cont.next("input").val("");

								

								$(this).closest('.day-list-item').remove();

							}

						);

And please note, we don't really need extra javascript logics to handle the submission. It is ready to submit now already. But before trying that, we need a PHP file: 

<?php
$scheduler_day = (isset($_REQUEST['schdl-day']) ? $_REQUEST['schdl-day'] : '');
print_r($scheduler_day);
exit;
?>

OK, try it:

one-way-before-subm


What server will print is:

Array
(
    [0] => day_2
    [1] => day_2
    [2] => day_1
    [3] => day_4
)


Improve User Experience


Not like Sortable, Droppable has one option for that, it is 'activeClass'. So, it comes simple, we create a CSS rule:  

.hightlight-target-background{

	background-color: rgb(255, 228, 122);

}

And use it when creating Droppable:

$( ".day-container" ).droppable({

	activeClass : "hightlight-target-background",

	drop: function( event, ui ) {

		var $cur_id = ui.draggable.attr("id");

		var $li = $( "<li class=\"day-list-item\"></li>" ).attr("id", $cur_id).appendTo( this );

		$( "<label></label>" ).text( ui.draggable.text() ).appendTo( $li );

		$( "<div class=\"remove\"></div>" ).appendTo( $li );

		
		var $ip = $(this).next("input").first();

		$ip.val($cur_id);
		

		var $num = $(this).find("li").size();

		if($num > 1)

		{

			var $first_li = $(this).find("li").first();

			$first_li.hide( 

							250, 

							function()

							{

								$(this).remove();

							} 

						);

		}

	}

});

But, we got some problems here!

be-hidden


The dragged item is underneath the container. To fix this problem, I found we just needed to add one more property to CSS rule .day-list-item:

z-index: 10;


Further Discovery About the Data Passed to Server


Let's check on the nature of the raw data server received from client in this case, add more lines to PHP file:

 

foreach($scheduler_day as $day)
{
	var_dump($day);

	if($day === "")
	{
		echo "this elem is empty string.<br />\n";
	}
	
	if(is_null($day))
	{
		echo "this elem is null.<br />\n"
	}
}

Array
(
    [0] => day_3
    [1] => 
    [2] => day_2
    [3] => day_2
)
<br />
string(5) "day_3"
the elem's type is: string.<br />
string(0) ""
this elem is empty string.<br />
the elem's type is: string.<br />
string(5) "day_2"
the elem's type is: string.<br />
string(5) "day_2"
the elem's type is: string.<br />



If, more than one input elements are grouped with one name, their values are becoming an array, and the empty-value input its value would be an empty String-type value in PHP. 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值