Angular tabs - sortable / moveable

Are there any Angular JS Tabs directives that allow them to be reordered (e.g. browser tabs)

If not for the initial implementation, it would be big

Using angular -ui-bootstap

<tabset> 
    <tab ng-repeat="tab in vm.tabs" active="tab.active" sortable-tab> </tab> 
    <tab disabled="true" ng-click"vm.addNewTab()" class="nonSortable-addTab-plusButton"></tab> 
</tabset>

How to make them reorderable?

EDIT: Bounty is added to use the original tablet syntax above.

+4
source share
4 answers

Using Angular UI Bootstrap tabsetwith only the directive sortable-tab:

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

, ngRepeat /, . () ng-repeat , , ngRepeat

// 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;
});

$index , :

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

HTML5, setData getData

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');
  },

  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);
    });
  };
}

: hover :hover . , CSS :hover - , Chrome.

, , ngRepeat, :

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

Plunker

+12

Angular, , . http://plnkr.co/edit/WnvZETQlxurhgcm1k6Hd?p=preview.

, , , , . :

$scope.tabs = [{
  header: 'Tab A',
  content: 'Content of Tab A'
},{
  header: 'Tab B',
  content: 'Content of Tab B'
}, {
  header: 'Tab C',
  content: 'Content of Tab C'
}];

HTML

HTML, ,

<tabs>
  <tab-buttons>
    <tab-button ng-repeat="tab in tabs">{{tab.header}}</tab-button>
  </tab-buttons>
  <tab-contents>
    <tab-content ng-repeat="tab in tabs">{{tab.content}}</tab-body>
  </tab-contents>
</tabs>

, , tabs. , require, , show , $index, ngRepeat .

app.directive('tabs', function($timeout) {
  return {
    restrict: 'E',
    controller: function($element, $scope) {
      var self = this;

      this.show = function(index) {
        // Show only current tab
        var contents = $element.find('tab-content');
        contents.removeClass('current');
        angular.element(contents[index]).addClass('current');

        // Mark correct header as current
        var buttons = $element.find('tab-button');
        buttons.removeClass('current');
        angular.element(buttons[index]).addClass('current');
      };

      $timeout(function() {
        self.show('0');
      });
    }
  };
});

app.directive('tabButton', function() {
  return {
    restrict: 'E',
    require: '^tabs',
    link: function(scope, element, attr, tabs) {
      element.on('click', function() {
        tabs.show(scope.$index);   
      });
    }
  };
});

, CSS , .current, http://plnkr.co/edit/WnvZETQlxurhgcm1k6Hd?p=preview, .

HTML5 drag + drop API, + , , . , , - , . sortable , , sortable-item, .

<tabs sortable="tabs">
  <tab-buttons>
    <tab-button ng-repeat="tab in list" sortable-item="$index">{{tab.header}}</tab-button>
  </tab-buttons>
  <tab-contents>
    <tab-content ng-repeat="tab in list">{{tab.content}}</tab-body>
  </tab-contents>
</tabs>

sortable sortableItem ( http://www.html5rocks.com/en/tutorials/dnd/basics/)

app.directive('sortable', function() {
  return {
    controller: function($scope, $attrs) {
      var listModel = null;
      $scope.$watch($attrs.sortable, function(sortable) {
        listModel = sortable;
      });
      this.move = function(fromIndex, toIndex) {
        // http://stackoverflow.com/a/7180095/1319998
        listModel.splice(toIndex, 0, listModel.splice(fromIndex, 1)[0]);
      };
    }
  };
});

app.directive('sortableItem', function($window) {
  return {
    require: '^sortable',
    link: function(scope, element, attrs, sortableController) {
      var index = null;
      scope.$watch(attrs.sortableItem, 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) {
          element.addClass('hover');
        },
        dragleave: function(e) {
          element.removeClass('hover');
        },
        drop: function(e) {
          e.preventDefault();
          e.stopPropagation();
          element.removeClass('hover');
          var sourceIndex = e.dataTransfer.getData('application/json');
          sortableController.move(sourceIndex, index);
        }
      };

      // For performance purposes, do not
      // call $apply for these
      var unwrappedListeners = {
        dragover: function(e) {
          e.preventDefault();
        }
      };

      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);
          });
        };
      }
    }
  };
});

, , sortableItem . , , sortable, . ngRepeat .

, , , . sortable , tabs, tabs .

+2

2 .

. http://angular-ui.imtqy.com/bootstrap/ . Bootstrap Angularjs . , , . /div ng-click, , .

. ng-repeat. , .

HTML:

<div class="tabs" ng-controller="TabController">
   <div class="add-tab" ng-click="add_tab()"></div>

   <div ng-repeat="tab in tabs" class="tab"></div>
</div>

Controller(JS):

app.controller('TabController',['$scope', function($scope){
$scope.tabs = [1, 1]
$scope.add_tab = function(){
$scope.tabs.push(1);
}
}]);

. ( , , , , ), jQuery / Angularjs, .

+1

Source: https://habr.com/ru/post/1534929/


All Articles