我遇到了一种奇怪的情况。我需要有两个可排序的列表,它们应该通过拖放或添加/删除事件来交换元素。
我创建了一个运行良好的指令。控制器事件也做正确的工作。当组合方法时,问题就开始了(按钮添加+拖放+按钮再次添加按钮)。 KA-BOOM!
我把这个plnkr放在一起:http://plnkr.co/edit/DumufP1kDdkz1INAXwmF?p=preview
单击元素,然后单击按钮操作(添加/删除)。
让我分享一些指令的代码只是为了好玩,但请访问链接以查看整个实现。有关如何在plnkr
中重现该问题的更多信息.directive('sortableList', function ($log) {
return {
restrict: 'A',
scope: {
fromList: '=',
toList: '='
},
link: function (scope, elm, attrs) {
var callback = {
receive: function (event, ui) {
//-- Get the scope of the list-item
var scopeItem = ui.item.scope();
//-- Get new list index
var newIdx = ui.item.index();
//-- Find position in the list
var prevIdx = scope.fromList.indexOf(scopeItem.obj);
//-- Remove from source list
scope.fromList.splice(prevIdx, 1);
//-- Add to target list
if (newIdx >= scope.toList.length) {
scope.toList.push(scopeItem.obj);
}
else {
scope.toList.splice(newIdx, 0, scopeItem.obj);
}
//ui.item.removeClass('selectedSortListItem').addClass('sortListItem');
scope.$apply();
},
stop: function (event, ui) {
//$log.log(ui);
}
};
//-- Apply jquery ui sortable plug-in to element
elm.sortable({
handle: ".handle",
connectWith: '.sortColumnsConnect',
dropOnEmpty: true,
cancel: ".ui-state-disabled",
receive: callback.receive,
stop: callback.stop
}).disableSelection();
//-- Sniff for list changes
/*scope.$watch(attrs.sortableList, function (newVal) {
//-- Apply callback
//if (angular.isUndefined(newVal)) return;
elm.sortable('option', 'receive', callback.receive);
if (!angular.isUndefined(attrs.trackSorting) && Boolean(attrs.trackSorting)) {
elm.sortable('option', 'stop', callback.stop);
}
});*/
}
}
})
非常感谢帮助。
答案 0 :(得分:0)
我终于成功了。我已经完成了这项工作plunker。 我认为它与两个指令的范围有关(自定义+ ng-repeat),但事实证明我需要让ng-repeat执行整个工作并且永远不会删除ng-repeat注释,否则angular指令将制动。
虽然我的指令需要注意的一件事是$ destroy甚至,因为指令本身持有一个对象的引用,最好在页面离开时删除或者某些东西以避免内存泄漏情况。
现在,让我们在这里分享一些有趣的代码..再次..
.directive('sortableList', function ($log, $parse,$timeout) {
return {
restrict: 'A',
scope: {
list: '='
},
link: function (scope, elm, attrs) {
/*
* We need to preserve a copy of ng-repeat comments
* in order to not brake the ng directive. Lets made a copy and
* and insert it back to the html list in the remove even.
*/
var comments = elm.contents().filter(function(){
return this.nodeType == 8;
});
var comment = undefined;
if (comments.length > 0){
comment = comments[0];
}
var callback = {
start: function(event, ui){
ui.item.sortable = {
received: false,
startIndex: ui.item.index()
};
},
receive: function (event, ui) {
ui.item.sortable.received = true;
},
update: function (event, ui) {
//$log.log(elm);
$log.log('update');
var scopeItem = ui.item.scope();
//-- Get new list index. Index in array not in html list
var newIdx = ui.item.index();
if (ui.item.sortable.received){
$log.log('received');
ui.sender.sortable('cancel');
ui.item.sortable.received = false;
//ui.item.sortable.doremove = true;
scope.$apply(function(){
//-- Add to target list
if (newIdx >= scope.list.length) {
scope.list.push(scopeItem.obj);
}
else {
$log.log(newIdx);
scope.list.splice(newIdx, 0, scopeItem.obj);
}
ui.item.removeClass('selectedSortListItem').addClass('sortListItem');
});
}
else {
//-- Sort list
if (ui.item.sortable.startIndex != newIdx){
$log.log('sort list');
scope.$apply(function(){
var idx = scope.list.indexOf(scopeItem.obj);
//-- end destroy
if (idx > -1){
scope.list.splice(idx, 1);
}
//-- Add to the new position
scope.list.splice(newIdx, 0, scopeItem.obj);
});
}
}
},
remove: function( event, ui ) {
var scopeItem = ui.item.scope();
/* Do the normal node removal */
//-- Seek
var idx = scope.list.indexOf(scopeItem.obj);
//-- end destroy
if (idx > -1){
scope.list.splice(idx, 1);
}
/*
* Insert back ng-repeat comments to the html list to avoid braking
* the angular directive.
*/
if (elm.children("li:not('.ui-state-disabled')").length === 0 && angular.isDefined(comment)){
$log.log('insert comment');
$log.log(comment);
elm.append(comment);
//$log.log(elm);
}
//$log.log('I have childrens: ' + elm.children("li:not('.ui-state-disabled')").length);
//$log.log('remove me please at:' + idx);
},
stop: function (event, ui) {
$log.log('stop');
}
};
scope.$watch('list.length', function() {
// Timeout to let ng-repeat modify the DOM
$timeout(function() {
$log.log('epa!');
//-- need to unselect those selected, otherwise Vishal will go like: Leo there is an error.. what? what? what?
elm.children("li.selectedSortListItem").toggleClass('selectedSortListItem').toggleClass('sortListItem');
elm.sortable('refresh');
});
});
//-- Apply jquery ui sortable plug-in to element
elm.sortable({
handle: ".handle",
connectWith: '.sortColumnsConnect',
dropOnEmpty: true,
cancel: ".ui-state-disabled",
helper: "clone",
start: callback.start,
receive: callback.receive,
update: callback.update,
stop: callback.stop,
remove: callback.remove
}).disableSelection();
}
}
})
看一下plunker,了解如何调用该指令及其目的。经过这么多的重新工厂后,我可能会忘记拆除一些东西......但现在似乎做得对了..至少它不像以前那样制动。
感谢。