How to capture td table elements using mousedown.dragselect event?

I have a directive that displays an HTML table in which every td element has id

What I want to do is use mousedown.dragselect/mouseup.dragselect to determine which items have been selected, and then select these selected items. What I have so far looks something like this:

 var $ele = $(this); scope.bindMultipleSelection = function() { element.bind('mousedown.dragselect', function() { $document.bind('mousemove.dragselect', scope.mousemove); $document.bind('mouseup.dragselect', scope.mouseup); }); }; scope.bindMultipleSelection(); scope.mousemove = function(e) { scope.selectElement($(this)); }; scope.mouseup = function(e) { }; scope.selectElement = function($ele) { if (!$ele.hasClass('eng-selected-item')) $ele.addClass('eng-selected-item'); //apply selection or de-selection to current element }; 

How can I get each td element selected by mousedown.dragselect and get their identifiers and then select them?

+7
angularjs angularjs-directive
source share
1 answer

I suspect that using anything related to drag and drop will not give you what you want. Drag and drop is actually used when moving items (for example, dragging and dropping files into "My Computer / Finder") when you use several options.

Thus, there are a number of things that require directives:

  • Listen to mousedown , mouseenter and mouseup events, events.

    • mousedown should listen on table cells and set the drag mode.
    • mouseenter should also listen for cells, and if the directive is in drag and drop mode, select "appropriate cells"
    • mouseup should turn off the drag mode and actually be on the whole body, in case the mouse is raised while the cursor is not above the table.
  • jQuery delegation is useful here, since it can perfectly delegate the above events to a table, so the code is much more cell-friendly, which are added after the initialization of this directive. (I would not include or use jQuery in an Angular project unless you have a clear reason like this).

  • Although you did not mention this, the “corresponding cells” I suspect that all the cells are “in between” where the mouse was clicked and the current cell selected in the rectangle, and not just the cells that were entered when the mouse was clicked. To find them, cellIndex and rowIndex can be used along with filtering all the cells from the table.

  • All listeners should be wrapped in $scope.$apply to ensure that Angular starts the digest loop after they run.

  • In order for the directive to bind identifiers of selected elements to the surrounding area, the directive can use bidirectional binding using the scope property and the = symbol, as explained in Angular docs

Putting it all together, let's:

 app.directive('dragSelect', function($window, $document) { return { scope: { dragSelectIds: '=' }, controller: function($scope, $element) { var cls = 'eng-selected-item'; var startCell = null; var dragging = false; function mouseUp(el) { dragging = false; } function mouseDown(el) { dragging = true; setStartCell(el); setEndCell(el); } function mouseEnter(el) { if (!dragging) return; setEndCell(el); } function setStartCell(el) { startCell = el; } function setEndCell(el) { $scope.dragSelectIds = []; $element.find('td').removeClass(cls); cellsBetween(startCell, el).each(function() { var el = angular.element(this); el.addClass(cls); $scope.dragSelectIds.push(el.attr('id')); }); } function cellsBetween(start, end) { var coordsStart = getCoords(start); var coordsEnd = getCoords(end); var topLeft = { column: $window.Math.min(coordsStart.column, coordsEnd.column), row: $window.Math.min(coordsStart.row, coordsEnd.row), }; var bottomRight = { column: $window.Math.max(coordsStart.column, coordsEnd.column), row: $window.Math.max(coordsStart.row, coordsEnd.row), }; return $element.find('td').filter(function() { var el = angular.element(this); var coords = getCoords(el); return coords.column >= topLeft.column && coords.column <= bottomRight.column && coords.row >= topLeft.row && coords.row <= bottomRight.row; }); } function getCoords(cell) { var row = cell.parents('row'); return { column: cell[0].cellIndex, row: cell.parent()[0].rowIndex }; } function wrap(fn) { return function() { var el = angular.element(this); $scope.$apply(function() { fn(el); }); } } $element.delegate('td', 'mousedown', wrap(mouseDown)); $element.delegate('td', 'mouseenter', wrap(mouseEnter)); $document.delegate('body', 'mouseup', wrap(mouseUp)); } } }); 

Another thing that will make it a little nicer is to position the cursor on the pointer and turn off text selection.

 [drag-select] { cursor: pointer; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } 

You can also see this in action in this working demo.

+12
source share

All Articles