1

It seems possible with a previous version of Angular UI (see here) but I tried with uib-tabset and it doesn't work. Any ideas?

This doesn't work:

 <uib-tabset sortable-tab>
    <uib-tab heading="Title 1">
      Some text 1
    </uib-tab>
    <uib-tab heading="Title 2">
      Some text 2
    </uib-tab>
 </uib-tabset>

PLUNK

mkimmet
  • 749
  • 3
  • 15
  • 27
ps0604
  • 1,227
  • 23
  • 133
  • 330

1 Answers1

2

It still works. You have to apply the directive. The directive in your example is not already built in to the ui. Here is a Plunker with it working with the new version.

In your HTML:

    <uib-tabset>
 <uib-tab sortable-tab ng-repeat="tab in data.tabs" heading="{{tab.title}}" active="tab.active" disabled="tab.disabled">
        <p>{{tab.content}}</p>
      </uib-tab>
      <uib-tab disabled="true">
        <uib-tab-heading>
          <i class="glyphicon glyphicon-plus"></i>
        </uib-tab-heading>
      </uib-tab>
         </uib-tabset>

You have to include the directive as well in your Controller:

   app.directive('sortableTab', function($timeout, $document) {
  return {
    link: function(scope, element, attrs, controller) {
      // Attempt to integrate with ngRepeat
      // https://github.com/angular/angular.js/blob/master/src/ng/directive/ngRepeat.js#L211
      var match = attrs.ngRepeat.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/);
      var tabs;
      scope.$watch(match[2], function(newTabs) {
        tabs = newTabs;
      });

      var index = scope.$index;
      scope.$watch('$index', function(newIndex) {
        index = newIndex;
      });

      attrs.$set('draggable', true);

      // Wrapped in $apply so Angular reacts to changes
      var wrappedListeners = {
        // On item being dragged
        dragstart: function(e) {
          e.dataTransfer.effectAllowed = 'move';
          e.dataTransfer.dropEffect = 'move';
          e.dataTransfer.setData('application/json', index);
          element.addClass('dragging');
        },
        dragend: function(e) {
          //e.stopPropagation();
          element.removeClass('dragging');
        },

        // On item being dragged over / dropped onto
        dragenter: function(e) {
        },
        dragleave: function(e) {
          element.removeClass('hover');
        },
        drop: function(e) {
          e.preventDefault();
          e.stopPropagation();
          var sourceIndex = e.dataTransfer.getData('application/json');
          move(sourceIndex, index);
          element.removeClass('hover');
        }
      };

      // For performance purposes, do not
      // call $apply for these
      var unwrappedListeners = {
        dragover: function(e) {
          e.preventDefault();
          element.addClass('hover');
        },
        /* Use .hover instead of :hover. :hover doesn't play well with 
           moving DOM from under mouse when hovered */
        mouseenter: function() {
          element.addClass('hover');
        },
        mouseleave: function() {
          element.removeClass('hover');
        }
      };

      angular.forEach(wrappedListeners, function(listener, event) {
        element.on(event, wrap(listener));
      });

      angular.forEach(unwrappedListeners, function(listener, event) {
        element.on(event, listener);
      });

      function wrap(fn) {
        return function(e) {
          scope.$apply(function() {
            fn(e);
          });
        };
      }

      function move(fromIndex, toIndex) {
        // http://stackoverflow.com/a/7180095/1319998
        tabs.splice(toIndex, 0, tabs.splice(fromIndex, 1)[0]);
      };

    }


     }

    });

That directive also uses ng-repeat for the tabs the tabs are dynamic:

      $scope.data = [];
  $scope.data.tabs = [
    { title:'Dynamic Title 1', content:'Dynamic content 1', active:true},
    { title:'Dynamic Title 2', content:'Dynamic content 2'},
    { title:'Dynamic Title 3', content:'Dynamic content 3'}
  ];
Rani Radcliff
  • 4,856
  • 5
  • 33
  • 60
  • thanks, I had to add `a { -webkit-user-drag: none; -khtml-user-drag: none; -moz-user-drag: none; -o-user-drag: none; user-drag: none; }` to eliminate Chrome ghost image on drag – ps0604 Apr 06 '17 at 23:16
  • by the way, in IE11 this solution does not work, I get `Invalid argument at wrappedListeners.dragstart (http://run.plnkr.co/hZc8Q0m06AIH504v/example.js:36:11)` who mantains this directive? – ps0604 Apr 06 '17 at 23:21
  • I'm not sure if anyone "maintains" it, but a little research may turn up the author. – Rani Radcliff Apr 07 '17 at 00:19
  • if you are getting "e.dataTransfer undefined", just add "e.dataTransfer = e.originalEvent.dataTransfer;" before using "e.dataTransfer". – A. El Idrissi May 16 '19 at 10:56