在 AngularJS 应用程序中拖放的自定义指令
Posted
技术标签:
【中文标题】在 AngularJS 应用程序中拖放的自定义指令【英文标题】:Custom directive to Drag and Drop in AngularJS app 【发布时间】:2017-10-27 19:18:50 【问题描述】:我在 AngularJS 中编写了一个应用程序,我正在处理的一项要求是将元素从左侧拖放到右侧容器中。左侧的所有元素都可以很好地放置到右侧的容器中。但是当我单击 x 图标将它们移回左侧容器时,我只能移动蓝色的项目和绿色的项目(“手动干预”),我无法移回左侧容器。我已将ng-click
附加到a link
以触发一个函数来分离所有克隆的项目并移动未克隆的项目。我认为我的 js 中代码的这部分$rootScope.removeDraggedItem
在“手动干预”元素从左到右移动时无法正确绑定,并且无法执行该功能。
这是我的JSFiddle的链接。
这是我的代码:
HTML
<div class="panel panel-default" ng-app="app" ng-controller="appCtrl">
<div class="panel-heading">Components configuration:</div>
<div class="panel-body">
<div class="row">
<div class="col-lg-3">
<div class="jumbotron" style="min-height: 300px;">
<div class="container">
<div class="">
<ul class="list-group" id="dropleft">
<li class="ui-state-default drag-n-drop" drag-option="dropleft" ng-repeat="component in components">
<span class="label label-primary">component.name
<a href="#" ng-click="$root.removeDraggedItem($event)"><i style="color: white" class="fa fa-times hidden" aria-hidden="true"></i></a>
</span>
</li>
<li class="ui-state-default drag-n-drop-clone" drag-option="clone" detach-element>
<span class="label label-success">Manual Intervention
<a href="#" ng-click="$root.removeDraggedItem($event)"><i style="color: white" class="fa fa-times hidden" aria-hidden="true"></i></a>
</span>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="col-lg-9">
<div class="jumbotron sortable" id="dropright" style="min-height: 300px;">
</div>
</div>
</div>
</div>
</div>
JS代码:
var app = angular.module('app', []);
app.controller('appCtrl', function($scope, $rootScope)
$scope.title = "Test";
$rootScope.removeDraggedItem = function($event)
var element = $(event.target).closest("li");
console.log(element.attr("drag-option"));
if (element.attr("drag-option") === "clone")
element.detach();
else
// Move to its original place
console.log("No clone detected! Moving element to its original place...");
var attrVal = element.attr("drag-option");
$(element).find("i").addClass("hidden");
$(element).detach().appendTo("#" + attrVal);
;
$scope.components = [
"name": "Component App1"
,
"name": "Component App2"
,
"name": "Component App3"
,
"name": "Component SQL1"
,
"name": "Component SQL2"
];
);
app.directive('dragNDrop', function()
return
restrict: 'C',
link: function(scope, element, attrs)
element.draggable(
connectToSortable: "#dropright",
revert: function(event, ui)
// on older version of jQuery use "draggable"
// $(this).data("draggable")
// on 2.x versions of jQuery use "ui-draggable"
// $(this).data("ui-draggable")
$(this).data("uiDraggable").originalPosition =
top: 0,
left: 0
;
// return boolean
return !event;
// that evaluate like this:
// return event !== false ? false : true;
);
$('#dropright').droppable(
drop: function(event, ui)
$(this).find("li").find("i").removeClass("hidden");
);
)
.directive('detachElement', function()
return
restrict: 'AC',
link: function($scope, element, attrs)
element.find("a").bind('click', function()
console.log("working now???");
);
)
.directive('dragNDropClone', function()
return
restrict: 'C',
link: function(scope, element, attrs)
element.draggable(
connectToSortable: "#dropright",
helper: 'clone',
invert: false
);
)
.directive('sortable', function()
return
restrict: 'C',
link: function(scope, element, attrs)
element.sortable(
cursor: 'move',
revert: true
);
);
CSS:
ul,
li
list-style-type: none;
/*
Release Dashboard
*/
.dashboard-header
margin-top: 31px;
.release-action-btn
border-color: #fff;
.status-color-red
background-color: #d9534f;
color: white;
.status-color-success
background-color: #5cb85c;
color: white;
.status-color-new
background-color: #999999;
color: white;
.status-color-inprogress
background-color: #337ab7;
color: white;
.panel-default > .panel-heading, .table-header, .navbar-inverse
background-color: #164c9c !important;
color: white;
更新:
通过将点击事件添加到 droppable 来解决问题。请参阅下面的代码。
$('#dropright').droppable(
drop: function (event, ui)
$(this).find("li").find("i").removeClass("hidden");
if ($(this).find("li").attr("drag-option") === "clone")
console.log($(this).find("li").find("a"));
$(this).find("li").find("a").on('click', function (evt)
evt.preventDefault();
$(this).closest("li").remove();
)
);
【问题讨论】:
我没有看到您用于<i>
元素上的 click
事件的代码,该元素在放置后未隐藏。
感谢您的回复。如果您看到<i>
的父元素,即<a>
,您将看到ng-click
触发功能。整个li
从左向右移动,这也移动了所有子元素。
绿色项目是克隆到右边还是移动到右边?
当我查看控制台时,当$root.removeDraggedItem($event)
被解雇时,我看到Error: event is not defined
。
在您的小提琴中发现了问题,您将$event
设置为属性名称。将其更改为event
解决错误并且功能正常运行。
【参考方案1】:
叉你小提琴。我在这段代码中发现了一个问题:
$rootScope.removeDraggedItem = function($event)
var element = $(event.target).closest("li");
console.log(element.attr("drag-option"));
if (element.attr("drag-option") === "clone")
element.detach();
else
// Move to its original place
console.log("No clone detected! Moving element to its original place...");
var attrVal = element.attr("drag-option");
$(element).find("i").addClass("hidden");
$(element).detach().appendTo("#" + attrVal);
;
您将函数属性定义为$event
,然后在函数内调用event
。我使用了以下内容:
https://jsfiddle.net/Twisty/hd234vq8/
JavaScript
var app = angular.module('app', []);
app.controller('appCtrl', function($scope, $rootScope)
$scope.title = "Test";
$rootScope.removeDraggedItem = function(event)
var element = $(event.target).closest("li");
console.log(element.attr("drag-option"));
if (element.attr("drag-option") === "clone")
element.detach();
else
// Move to its original place
console.log("No clone detected! Moving element to its original place...");
var attrVal = $("#" + element.attr("drag-option"));
element.find("i").addClass("hidden");
var attrPos = attrVal.position();
element.css("position", "absolute");
element.animate(
//top: (attrPos.top + attrVal.find("li:last").height()),
top: "-=250",
left: attrPos.left
, function()
element.detach().appendTo(attrVal);
element.attr("style", "").css("position", "relative");
);
;
$scope.components = [
"name": "Component App1"
,
"name": "Component App2"
,
"name": "Component App3"
,
"name": "Component SQL1"
,
"name": "Component SQL2"
];
);
app.directive('dragNDrop', function()
return
restrict: 'C',
link: function(scope, element, attrs)
element.draggable(
connectToSortable: "#dropright",
revert: function(event, ui)
// on older version of jQuery use "draggable"
// $(this).data("draggable")
// on 2.x versions of jQuery use "ui-draggable"
// $(this).data("ui-draggable")
$(this).data("uiDraggable").originalPosition =
top: 0,
left: 0
;
// return boolean
return !event;
// that evaluate like this:
// return event !== false ? false : true;
);
$('#dropright').droppable(
drop: function(event, ui)
$(this).find("li").find("i").removeClass("hidden");
);
)
.directive('detachElement', function()
return
restrict: 'AC',
link: function($scope, element, attrs)
element.find("a").bind('click', function()
console.log("working now???");
);
)
.directive('dragNDropClone', function()
return
restrict: 'C',
link: function(scope, element, attrs)
element.draggable(
connectToSortable: "#dropright",
helper: 'clone',
invert: false
);
)
.directive('sortable', function()
return
restrict: 'C',
link: function(scope, element, attrs)
element.sortable(
cursor: 'move',
revert: true
);
);
如果用户将一个项目拖到另一个列表中,我喜欢为返回设置动画。您将在上面的代码中看到这一点。
更新
根据您的更新,我建议在 droppable 中执行以下操作:
$('#dropright').droppable(
drop: function(event, ui)
var item = $(this).find("li");
item.find("i").removeClass("hidden");
if (item.attr("drag-option") === "clone")
console.log(item.find("a"));
item.find("a").click(function(evt)
evt.preventDefault();
item.remove();
);
);
这将是确保事件绑定回调的好选择。您可以在此处使用.click()
,因为您是直接分配它。如果您在元素存在之前分配它,您可以使用.on()
。以太方式仍然可以工作。
我注意到的另一件事是,在#dropright
中,没有<ul>
元素。这不是问题,但它确实很奇怪。觉得值得一提。
【讨论】:
当绿色项目被克隆到右侧时,我无法从右侧删除该项目。这对你有用吗? 将不得不测试。怀疑点击回调没有被克隆。 测试完毕,我看到if (element.attr("drag-option") === "clone") element.detach();
这个项目。您希望删除克隆的项目还是将其作为额外项目添加回原始列表?
您好,感谢您抽出宝贵时间帮我解决这个问题 :) 我希望删除克隆的项目,因为原始列表已经包含该列表。
@Ray 那么我会使用if (element.attr("drag-option") === "clone") element.remove();
以上是关于在 AngularJS 应用程序中拖放的自定义指令的主要内容,如果未能解决你的问题,请参考以下文章
用于 Silverlight 中拖放的 TranslateTransform