AngularJS指令与ng-repeat – misbehavior共享范围

我遇到了一个奇怪的情况。 我需要有两个可排序的列表,它们应该通过拖放或添加/删除事件来交换元素。

我创建了一个运行良好的指令。 控制器事件也能做正确的工作。 当组合方法时,问题就开始了(按钮添加+拖放+按钮再次添加按钮)。 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); } });*/ } } }) 

感谢帮助。

我终于成功了。 我把这一切都用在了这个吸管上 。 我认为它与两个指令的范围有关(自定义+ ng-repeat),但事实certificate我需要让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,了解如何调用该指令及其目的。 经过这么多的重新工厂后,我可能会忘记拆除一些东西……但现在看起来似乎正在做正确的事情……至少它不像以前那样制动。

谢谢。