How to use ng2-dragula and angular element resizer

1.6k Views Asked by At

I'm using Dragula for drag and drop on my tables. Also I'm using plugin angular resizier element for resizing table columns. All this I've been working in Angular2.

So what I want is this. My current situation is like this gray column on image. Whole column width is draggable and that makes me a problem when resizing column. so when I'm trying to resize my column it acts like drag and drop. I want that my colum is like this yellow one. To have some space for resizing.

And here si part of my html code:

<div class="row" [dragula]='"one-bag"' [dragulaModel]='names'>
    <div class="col" *ngFor="let name of names"
         mwlResizable
         [validateResize]="validate"
         [resizeEdges]="{right: true}"
         [enableGhostResize]="false">
         <label>{{name}}</label>
    </div>  
</div>

here is resizer I've been using. https://github.com/mattlewis92/angular-resizable-element

Question: How could I use ng2-dragula and resizer on same table columns?

2

There are 2 best solutions below

0
On

You could use the moves method to only allow dragging from a certain region like this:

constructor(private dragulaService: DragulaService) {
this.dragulaService.createGroup("CARDS", {
  direction: "vertical",
  moves: (el, source, handle): boolean => handle.className.indexOf("ri-card-header") > -1
});
}

In this way you can specify a CSS selector to determine whether to allow moving or not. If the moves method returns false then the events will be forwarded and the move would not begin.

3
On

I've been having the same problem myself, but with ngDraggable instead of dragula...

Only solution i have thought of is to set Handlers for both, like mwlResizeableHandler HTMLElement for the resizeable module and another for the ngDraggable module, stop propagation of click events on both and force them to update the same Style object within the Component, which is then passed with ngStyle on to the element to determine its position on the browser.

I think that the source of the problem is the fact that ngDraggable implements a transformation : translate(x,y) while resizeable refers to an Styles Object, meaning top/left positioning.

I haven't implemented the solution yet, but once i configure it in code i will post an update.

EDIT/UPDATE:

okay, what i did was implement my own draggable functions, which proved easier on the long run. this is my resizable:

<div @fade id="{{index}}" class="box" [ngStyle]="style"
    mwlResizable 
    [validateResize]="validate"
    [resizeCursorPrecision]="resizeCursor"
    [enableGhostResize]="true"
    [ghostElementPositioning]="style.position"
    (resizeEnd)="onResizeEnd($event)"
    (click)="setSelected($event)"
    [ngClass]="{selected : selected}">
    <div 
    style="cursor: move; height: 50px; width: 50px; border: 2px solid black; background-color: green;"
    (mousedown)="onMouseDown($event)" 
    (mousemove)="onMove($event)"
    (mouseup)="finalPosition($event)"
    (mouseleave)="finalPosition($event)">
    </div>
    <img class="resize-handle-top-left" 
    mwlResizeHandle  
    [resizeEdges]="{top: true, left: true}"
    src="http://i.imgur.com/eqzz2dl.gif">
    <img class="resize-handle-top-right" 
    mwlResizeHandle  
    [resizeEdges]="{top: true, right: true}"
    src="http://i.imgur.com/eqzz2dl.gif">
    <img class="resize-handle-bottom-left" 
    mwlResizeHandle  
    [resizeEdges]="{bottom: true, left: true}"
    src="http://i.imgur.com/eqzz2dl.gif">
    <img class="resize-handle-bottom-right" 
    mwlResizeHandle  
    [resizeEdges]="{bottom: true, right: true}"
    src="http://i.imgur.com/eqzz2dl.gif">
  </div>
</div>

code that implements the resizing:

public onResizeEnd(event: ResizeEvent): void {
      this.style = {
      position: 'absolute',
      left: `${event.rectangle.left}px`,
      right: `${event.rectangle.right}px`,
      top: `${event.rectangle.top}px`,
      bottom: `${event.rectangle.bottom}px`,
      width: `${event.rectangle.width}px`,
      height: `${event.rectangle.height}px`
    };

so what i did was just a temporary box in the middle of the div and set some event listeners on it, mousedown, mousemove, mouseup. The checkBoundaries functions are just there to check that the drag does not exceed the parents DIV limitations:

checkBoundariesLeft(styleAttr: number, tempMove: number): number {
    if ((styleAttr + tempMove) > 0 && (styleAttr + tempMove) < (this.api.imageW - Number.parseInt(this.style.width))) {
      this.previousLeft = (styleAttr + tempMove);
      return this.previousLeft;
    }
    return this.previousLeft;
  }
  checkBoundariesRight(styleAttr: number, tempMove: number): number {
    if ((styleAttr + tempMove) > Number.parseInt(this.style.width) && (styleAttr + tempMove) < this.api.imageW) {
      this.previousRight = (styleAttr + tempMove);
      return this.previousRight;
    }
    return this.previousRight;
  }

  checkBoundariesTop(styleAttr: number, tempMove: number): number {
    if ((styleAttr + tempMove) > 0 && (styleAttr + tempMove) < (this.api.imageH - Number.parseInt(this.style.height))) {
      this.previousTop = (styleAttr + tempMove);
      return this.previousTop;
    }
    return this.previousTop;
  }

  checkBoundariesBottom(styleAttr: number, tempMove: number): number {
    if ((styleAttr + tempMove) > Number.parseInt(this.style.height) && (styleAttr + tempMove) < this.api.imageH) {
      this.previousBottom = (styleAttr + tempMove);
      return this.previousBottom;
    }
    return this.previousBottom;
  }

  public onMouseDown(event: MouseEvent): void {
    event.stopPropagation();
    this.moveElementInitiated = true;
    this.tempCoords = {
      left : event.offsetX,
      top : event.offsetY
    };
  }

  public onMove(event: MouseEvent): void {
    if (this.moveElementInitiated) {
      const tempLeft = (event.offsetX - this.tempCoords.left) / this.ratio;
      const tempTop = (event.offsetY - this.tempCoords.top) / this.ratio;
      this.style = {
        position: 'absolute',
        left: `${this.checkBoundariesLeft(Number.parseInt(this.style.left), tempLeft)}px`,
        right: `${this.checkBoundariesRight(Number.parseInt(this.style.right), tempLeft)}px`,
        top: `${this.checkBoundariesTop(Number.parseInt(this.style.top), tempTop)}px`,
        bottom: `${this.checkBoundariesBottom(Number.parseInt(this.style.bottom), tempTop)}px`,
        width: this.style.width,
        height: this.style.height
      };
    }
  }

  public finalPosition(event): void {
    this.moveElementInitiated = false;
  }

I should note that all functions Update the same style object within the component.