2

I am writing a site in Angular using JQuery UI, which allows arrangeable items. I initially populate my DOM from the contents of an array, and then allow the user to drag around the DOM elements. I want the dragging of the DOM elements to correspond with the updating of the order of the array.

I am using an ng-repeat directive to translate the array into a DOM tree, and originally thought that array element rearranging would happen automatically. Can I do this using Angular? Here is my code:

<!DOCTYPE html>
<html ng-app = "">
<head>
  <style>
    #BlockContainer li
    {
      /*make there be no selection on each list item*/
      -moz-user-select: none;
      -khtml-user-select: none;
      -webkit-user-select: none;
      user-select: none;
    }

    li 
    {
      list-style-type: none;
    }

    #ArchtypeContainer li, #BlockContainer li
    {
      display: block;
    }
  </style>
  <link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" data-require="[email protected]" data-semver="3.1.1" />
  <script src="//code.jquery.com/jquery-1.10.2.js"></script>
  <script src="//code.jquery.com/ui/1.11.0/jquery-ui.js"></script>
  <script src="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js" data-require="[email protected]" data-semver="3.1.1"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.17/angular.min.js" data-require="[email protected]" data-semver="1.2.17"></script>
</head>

<body ng-controller="Controller">
  <script>
      function Controller($scope)
      {
        //sets out the data archtypes for everything
        $scope.BlockArchtypes = [{"Name": "Move Seconds", "Arguments": [{"Placeholder": "Speed (0 - 100)"}, {"Placeholder": "Seconds"}]}, {"Name": "Move Distance", "Arguments": [{"Placeholder": "Distance (Feet)"}, {"Placeholder": "Speed (0 - 100)"}]}];
        $scope.BlockData = [];

        $scope.NewBlock = function (index)
        {
          $scope.ToCopy = angular.copy($scope.BlockArchtypes[index]); 
          $scope.BlockData.push($scope.ToCopy);


        }

        $scope.Update = function(){
          console.log($scope.BlockData);
        }
      }

      $(document).ready(function()
      {
        $("#BlockContainer").sortable(
        {
          change: function(event, ui) 
          {
            $scope.apply($scope.BlockData);
          }
        });

      });

  </script>

  <h3>Archtypes</h3>

  <ul id = "ArchtypeContainer">
    <li ng-repeat="Block in BlockArchtypes">
      <div>{{Block.Name}}</div>
      <div ng-repeat="Argument in Block.Arguments"><input  type="text" ng-model = "Argument.Value" placeholder="{{Argument.Placeholder}}" /></div>
      <button ng-click = "NewBlock($index);">Add</button>
    </li>
  </ul>

  <h3>Program</h3>
  <button ng-click = "Update()">Update</button>
  <ul id = "BlockContainer">
    <li ng-repeat="Block in BlockData track by $index">
      <div>{{Block.Name}}</div>
      <div ng-repeat="Argument in Block.Arguments"><input type="text" ng-model = "Argument.Value" placeholder="{{Argument.Placeholder}}" /></div>
    </li>
  </ul>
</body>
</html>

1 Answer 1

2

It's probably the best way to use the Drag and Drop library for AngularJS which is basically jQuery UI's Draggable and Dropable, but made to work directly with Angular.

Draggable example:

<div class="btn btn-primary" data-drag="true" data-jqyoui-options="{revert: 'invalid'}" 
 ng-model="list1" jqyoui-draggable="{animate:true}" ng-hide="!list1.title">
    {{list1.title}}
</div>

Droppable example:

<div class="thumbnail" data-drop="true" data-jqyoui-options ng-model="list2" 
 jqyoui-droppable style='height:50px;'>
    <div class="btn btn-success" data-drag="false" data-jqyoui-options ng-model="list2" 
     jqyoui-draggable ng-hide="!list2.title">
        {{list2.title}}
    </div>
</div>

Angular code:

App.controller('OverviewCtrl', function($scope) {
    $scope.list1 = {title: 'AngularJS - Drag Me'};
    $scope.list2 = {};
});

There are more examples online.


And the reason why you didn't make it work with jQuery UI is because Angular is unaware of DOM changes unless the changes were done by Angular itself, or you told it about the changes (via $scope.$apply(), for example)... So, in order to make it all work, you'd need to attach watchers or create callback functions to all the movable elements, and make Angular do the necessary scope variable updates upon each change - that's why I suggested that library, it does pretty much everything for you.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.