title: AngularJS Nested jQuery UI Sortables with Recursion
body: <p>I've got a AngularJS directive that hooks up sortables.  </p>
  
  <p>I'm trying to create a directive that will allow me to drag and drop new items into a sortable.  If that item is a 'section' it should allow further drag and drops into it recursively.  The section inits a sortable itself and I attempt to connect the sortables.  Problem is it never connects...  I've built similar demos with jqueryUI alone so I know that its possible, my angular implementation is probably just messing something up.  Any ideas?</p>
  
  <p>sortable directive:</p>
  
  <pre><code>app.constant('sortableConfig', {
      connectWith: '.sortables'
  });
  
  app.directive('sortable', ['$timeout','sortableConfig', function ($timeout, sortableConfig) {
      return {
          restrict: 'AE',
          scope: {
              ngModel: '=',
              options: '='
          },
          link: function ($scope, $element, $attributes) {
              var ngModel = $scope.ngModel;
  
              var options = angular.extend(sortableConfig, 
                      $scope.$eval($attributes.options)),
                  sortableIn = 0;
  
              console.log(ngModel)
  
              options.start = function(e, ui) {
                  // Save position of dragged item
                  ui.item.sortable = { index: ui.item.index() };
              };
  
              options.update = function(e, ui) {
                  // For some reason the reference to ngModel in stop() is wrong
                  ui.item.sortable.resort = ngModel;
              };
  
              options.receive = function(e, ui) {
                  sortableIn = 1;
                  ui.item.sortable.relocate = true;
                  // added item to array into correct position and set up flag
                  ngModel.splice(ui.item.index(), 0, ui.item.sortable.moved);
              };
  
              options.remove = function(e, ui) {
                  // copy data into item
                  if (ngModel.length === 1) {
                      ui.item.sortable.moved = ngModel.splice(0, 1)[0];
                  } else {
                      ui.item.sortable.moved =  ngModel.splice(ui.item.sortable.index, 1)[0];
                  }
              };
  
              options.over = function(e, ui) {
                  sortableIn = 1;
              };
  
              options.out = function(e, ui) {
                  sortableIn = 0;
              };
  
              options.beforeStop = function(e, ui) {
                  // http://snipplr.com/view/49923/
                  if (sortableIn == 0) { 
                      console.log('REMOVE!', ui.item.sortable.resort)
                      //ui.item.remove(); 
                      //ngModel.splice(ui.item.index(), 1);
                  }
              };
  
              options.stop = function(e, ui) {
                  // digest all prepared changes
                  if (ui.item.sortable.resort &amp;&amp; !ui.item.sortable.relocate) {
                      // Fetch saved and current position of dropped element
                      var end, start;
                      start = ui.item.sortable.index;
                      end = ui.item.index();
  
                      // Reorder array and apply change to scope
                      ui.item.sortable.resort.splice(
                          end, 0, ui.item.sortable.resort.splice(start, 1)[0]);
                  }
              };
  
              $timeout(function(){
                  console.log(options)
                  $element.sortable(options);
              })
          }
      }
  }]);
  </code></pre>
  
  <p>sortable template:</p>
  
  <pre><code> &lt;ul sortable class="sortable" ng-model="ngModel"&gt;
  &lt;li class="pull-left" ng-repeat="item in ngModel" ng-model="item" ng-style="drawLayout(item)"&gt;
      &lt;div ng-if="isField(item)"
           class="btn btn-info btn-draggable layout-field"
           ng-click="showDetails(item)"&gt;{{item.name}}&lt;/div&gt;
  
      &lt;div droppable 
           ng-model="item.children"
           dropped="layoutDropped(dragModel, dropModel)" 
           ng-if="item.typeOf == 'section'"
           class="panel panel-default layout-section"&gt;
  
          &lt;div class="panel-heading" ng-click="showDetails(item)"&gt;
              {{item.name}}
              &lt;div ng-show="item.helpTextOpt != 'none'"&gt;
                  &lt;hr /&gt;
                  &lt;p&gt;{{item.helpText}}&lt;/p&gt;
              &lt;/div&gt;
          &lt;/div&gt;
          &lt;div class="panel-body" onload="ngModel=item.children"
               ng-include="'views/app-builder/layout.html'"&gt;
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/li&gt;
  </code></pre>