【问题标题】:Custom directive to Drag and Drop in AngularJS app在 AngularJS 应用程序中拖放的自定义指令
【发布时间】: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();
                                })
                            }
                        }
                    });

【问题讨论】:

  • 我没有看到您用于 &lt;i&gt; 元素上的 click 事件的代码,该元素在放置后未隐藏。
  • 感谢您的回复。如果您看到&lt;i&gt; 的父元素,即&lt;a&gt;,您将看到ng-click 触发功能。整个li 从左向右移动,这也移动了所有子元素。
  • 绿色项目是克隆到右边还是移动到右边?
  • 当我查看控制台时,当$root.removeDraggedItem($event) 被解雇时,我看到Error: event is not defined
  • 在您的小提琴中发现了问题,您将$event 设置为属性名称。将其更改为event 解决错误并且功能正常运行。

标签: jquery angularjs jquery-ui angularjs-directive


【解决方案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 中,没有&lt;ul&gt; 元素。这不是问题,但它确实很奇怪。觉得值得一提。

【讨论】:

  • 当绿色项目被克隆到右侧时,我无法从右侧删除该项目。这对你有用吗?
  • 将不得不测试。怀疑点击回调没有被克隆。
  • 测试完毕,我看到if (element.attr("drag-option") === "clone") { element.detach(); }这个项目。您希望删除克隆的项目还是将其作为额外项目添加回原始列表?
  • 您好,感谢您抽出宝贵时间帮我解决这个问题 :) 我希望删除克隆的项目,因为原始列表已经包含该列表。
  • @Ray 那么我会使用if (element.attr("drag-option") === "clone") { element.remove(); }
猜你喜欢
  • 2018-03-01
  • 2013-01-20
  • 2014-06-24
  • 1970-01-01
  • 1970-01-01
  • 2020-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多