1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
	<title>Sortable</title>

	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
	<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js"></script>
	<script type="text/javascript" src="scripts/jquery.tmpl.min.js"></script>
	<script type="text/javascript" src="scripts/knockout-1.1.1.js"></script>
	<style type="text/css">
		#sortable1, #sortable2  {
			list-style-type: none; 
			margin: 0; 
			padding: 0; 
			float: left; 
			margin-right: 10px; 
			background: #eee; 
			padding: 5px; 
			width: 143px;
		}
		#sortable1 li, #sortable2 li {
			margin: 5px; 
			padding: 5px; 
			font-size: 1.2em; 
			width: 120px; 
		}
	</style>
</head>
<body>
	<div class="container">
			<ul id="sortable1" class="connectedSortable" data-bind="sortable : Products"></ul>
			<ul id="sortable2" class="connectedSortable" data-bind="sortable : Selected"></ul>
	</div>
	<br style="clear: both"/>
	<a href="#" data-bind="click: save">Show Results</a>
	<br/>
	<br/>
	<div id="log"></div>
	<script type="text/html" id="tmpProducts">
		 {{each $data}}
			<li data-id="${ Id }" class="ui-state-default">${ Name }</li>
		 {{/each}}
	</script>
	<script type="text/javascript">
		var debug = true;
		var logger = function (log) {
			if (debug !== undefined && debug) {
				$('<div></div>').appendTo('#log').text(new Date().toGMTString() + ' : ' + log);
			}
		};
		$(document).ready(function () {

			var product = function (data) {
				this.Id = data.Id;
				this.Name = data.Name;
				this.Price = data.Price;
			};

			var myViewModel = {
				Products: ko.observableArray([
					new product({ Id : "1", Name: "Windows XP", Price: 199.99 }),
					new product({ Id : "2", Name: "Windows Vista", Price: 299.99 }),
					new product({ Id : "3", Name: "Windows 7", Price: 239.99 })
				]),
				Selected: ko.observableArray([]),
				Moving: ko.observable(),
				save: function () {
					alert(ko.toJSON(this.Selected));
				}
			};

			ko.bindingHandlers.sortable = {
				init: function (element, valueAccessor, allBindingsAccessor, viewModel) {
				
					var $element = $(element),
						data = valueAccessor(),
						connector = '.connectedSortable',
						options = {
							connectWith: connector,
							dropOnEmpty: true,
							start : function(event, ui) {
								var id = $(ui.item).attr('data-id'),
									data = ko.utils.unwrapObservable(valueAccessor());
								for (var i=0, l = data.length; i < l; i++) {
									if (data[i].Id === id) {
										break;
									}
								}
								myViewModel.Moving(data[i]);
							},
							remove: function(event, ui){
								logger('remove ' + $(ui.item).attr('data-id') + ' ' + myViewModel.Moving().Name);
								data.remove(myViewModel.Moving());
							},
							receive: function (event, ui) {
								logger('received ' + $(ui.item).attr('data-id') + ' ' + myViewModel.Moving().Name);
								data.push(myViewModel.Moving());
							}
						};
						
					// render initial lists
					var templateEngine = new ko.jqueryTmplTemplateEngine();
					ko.renderTemplate("tmpProducts", data, { templateEngine: templateEngine }, element, "replaceChildren");
					
					// bind your sortable here
					$element.sortable(options).disableSelection();
				}
			};
			ko.applyBindings(myViewModel);
		});
		
	</script>
</body>
</html>