Skip to content
This repository was archived by the owner on Sep 8, 2020. It is now read-only.

Commit 988644f

Browse files
committed
Merge pull request #199 from thgreasi/nested
feat(sortable): add workaround for nested sortings not triggering update
2 parents d4462d5 + 191f70a commit 988644f

File tree

3 files changed

+120
-3
lines changed

3 files changed

+120
-3
lines changed

src/sortable.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,14 @@ angular.module('ui.sortable', [])
174174
};
175175

176176
callbacks.remove = function(e, ui) {
177+
// Workaround for a problem observed in nested connected lists.
178+
// There should be an 'update' event before 'remove' when moving
179+
// elements. If the event did not fire, cancel sorting.
180+
if (!('dropindex' in ui.item.sortable)) {
181+
element.sortable('cancel');
182+
ui.item.sortable.cancel();
183+
}
184+
177185
// Remove the item from this list's model and copy data into item,
178186
// so the next list can retrive it
179187
if (!ui.item.sortable.isCanceled()) {

test/sortable.e2e.multi.spec.js

Lines changed: 106 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ describe('uiSortable', function() {
66
beforeEach(module('ui.sortable'));
77
beforeEach(module('ui.sortable.testHelper'));
88

9-
var EXTRA_DY_PERCENTAGE, listContent;
9+
var EXTRA_DY_PERCENTAGE, listContent, listInnerContent;
1010

1111
beforeEach(inject(function (sortableTestHelper) {
1212
EXTRA_DY_PERCENTAGE = sortableTestHelper.EXTRA_DY_PERCENTAGE;
1313
listContent = sortableTestHelper.listContent;
14+
listInnerContent = sortableTestHelper.listInnerContent;
1415
}));
1516

1617
describe('Multiple sortables related', function() {
@@ -346,6 +347,110 @@ describe('uiSortable', function() {
346347
});
347348
});
348349

350+
it('should update model when sorting between nested sortables', function() {
351+
inject(function($compile, $rootScope) {
352+
var elementTree, li1, li2, dy;
353+
354+
elementTree = $compile(''.concat(
355+
'<ul ui-sortable="sortableOptions" ng-model="items" class="apps-container outterList" style="float: left;margin-left: 10px;padding-bottom: 10px;">',
356+
'<li ng-repeat="item in items">',
357+
'<div>',
358+
'<span class="itemContent lvl1ItemContent">{{item.text}}</span>',
359+
'<ul ui-sortable="sortableOptions" ng-model="item.items" class="apps-container innerList" style="margin-left: 10px;padding-bottom: 10px;">',
360+
'<li ng-repeat="i in item.items">',
361+
'<span class="itemContent lvl2ItemContent">{{i.text}}</span>',
362+
'</li>',
363+
'</ul>',
364+
'</div>',
365+
'</li>',
366+
'</ul>',
367+
'<div style="clear: both;"></div>'))($rootScope);
368+
369+
$rootScope.$apply(function() {
370+
$rootScope.items = [
371+
{
372+
text: 'Item 1',
373+
items: []
374+
},
375+
{
376+
text: 'Item 2',
377+
items: [
378+
{ text: 'Item 2.1', items: [] },
379+
{ text: 'Item 2.2', items: [] }
380+
]
381+
}
382+
];
383+
384+
$rootScope.sortableOptions = {
385+
connectWith: '.apps-container'
386+
};
387+
});
388+
389+
host.append(elementTree);
390+
391+
// this should drag the item out of the list and
392+
// the item should return back to its original position
393+
li1 = elementTree.find('.innerList:last').find(':last');
394+
li1.simulate('drag', { dx: -200, moves: 30 });
395+
expect($rootScope.items.map(function(x){ return x.text; }))
396+
.toEqual(['Item 1', 'Item 2']);
397+
expect($rootScope.items.map(function(x){ return x.text; }))
398+
.toEqual(listInnerContent(elementTree, '.lvl1ItemContent'));
399+
expect($rootScope.items[0].items.map(function(x){ return x.text; }))
400+
.toEqual([]);
401+
expect($rootScope.items[0].items.map(function(x){ return x.text; }))
402+
.toEqual(listInnerContent(elementTree.find('.innerList:eq(0)'), '.lvl2ItemContent'));
403+
expect($rootScope.items[1].items.map(function(x){ return x.text; }))
404+
.toEqual(['Item 2.1', 'Item 2.2']);
405+
expect($rootScope.items[1].items.map(function(x){ return x.text; }))
406+
.toEqual(listInnerContent(elementTree.find('.innerList:eq(1)'), '.lvl2ItemContent'));
407+
408+
// this should drag the item from the inner list and
409+
// drop it to the outter list
410+
li1 = elementTree.find('.innerList:last').find(':last');
411+
li2 = elementTree.find('> li:last');
412+
dy = EXTRA_DY_PERCENTAGE * li1.outerHeight() + (li2.position().top - li1.position().top);
413+
li1.simulate('drag', { dy: dy });
414+
expect($rootScope.items.map(function(x){ return x.text; }))
415+
.toEqual(['Item 1', 'Item 2.2', 'Item 2']);
416+
expect($rootScope.items.map(function(x){ return x.text; }))
417+
.toEqual(listInnerContent(elementTree, '.lvl1ItemContent'));
418+
expect($rootScope.items[0].items.map(function(x){ return x.text; }))
419+
.toEqual([]);
420+
expect($rootScope.items[0].items.map(function(x){ return x.text; }))
421+
.toEqual(listInnerContent(elementTree.find('.innerList:eq(0)'), '.lvl2ItemContent'));
422+
expect($rootScope.items[1].items.map(function(x){ return x.text; }))
423+
.toEqual([]);
424+
expect($rootScope.items[1].items.map(function(x){ return x.text; }))
425+
.toEqual(listInnerContent(elementTree.find('.innerList:eq(1)'), '.lvl2ItemContent'));
426+
expect($rootScope.items[2].items.map(function(x){ return x.text; }))
427+
.toEqual(['Item 2.1']);
428+
expect($rootScope.items[2].items.map(function(x){ return x.text; }))
429+
.toEqual(listInnerContent(elementTree.find('.innerList:eq(2)'), '.lvl2ItemContent'));
430+
431+
// this should drag the item from the outter list and
432+
// drop it to the inner list
433+
li1 = elementTree.find('> li:first');
434+
li2 = elementTree.find('.innerList:last').find(':last');
435+
dy = -EXTRA_DY_PERCENTAGE * li1.outerHeight() + (li2.position().top - li1.position().top);
436+
li1.simulate('drag', { dy: dy });
437+
expect($rootScope.items.map(function(x){ return x.text; }))
438+
.toEqual(['Item 2.2', 'Item 2']);
439+
expect($rootScope.items.map(function(x){ return x.text; }))
440+
.toEqual(listInnerContent(elementTree, '.lvl1ItemContent'));
441+
expect($rootScope.items[0].items.map(function(x){ return x.text; }))
442+
.toEqual([]);
443+
expect($rootScope.items[0].items.map(function(x){ return x.text; }))
444+
.toEqual(listInnerContent(elementTree.find('.innerList:eq(0)'), '.lvl2ItemContent'));
445+
expect($rootScope.items[1].items.map(function(x){ return x.text; }))
446+
.toEqual(['Item 1', 'Item 2.1']);
447+
expect($rootScope.items[1].items.map(function(x){ return x.text; }))
448+
.toEqual(listInnerContent(elementTree.find('.innerList:eq(1)'), '.lvl2ItemContent'));
449+
450+
$(elementTree).remove();
451+
});
452+
});
453+
349454
});
350455

351456
});

test/sortable.test-helper.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@ angular.module('ui.sortable.testHelper', [])
1111
return [];
1212
}
1313

14-
function listInnerContent (list) {
14+
function listInnerContent (list, contentSelector) {
15+
if (!contentSelector) {
16+
contentSelector = '.itemContent';
17+
}
18+
1519
if (list && list.length) {
16-
return list.children().map(function(){ return $(this).find('.itemContent').html(); }).toArray();
20+
return list.children().map(function(){ return $(this).find(contentSelector).html(); }).toArray();
1721
}
1822
return [];
1923
}

0 commit comments

Comments
 (0)