Отмена перетаскивания на нажатие клавиши Angular CDK Drag and Drop

Я работаю в приложении, реализующем новое перетаскивание из углового материала CDK, и я пытаюсь отменить событие перетаскивания нажатия элемента EscЯ имею в виду, я начинаю перетаскивать элемент, но если я нажимаю Esc в то время как я перетаскиваю элемент, он должен вернуться в положение, откуда я начинаю перетаскивать его, пока я не нашел способа сделать это, кто-нибудь знает, как я могу это сделать. Там нет ничего в документации CDK об этом ни одной идеи. я пытаюсь сделать что-то подобное

шаблон

<div cdkDropList class="example-list" (cdkDropListDropped)="drop($event)">
  <div class="example-box" *ngFor="let movie of movies" (cdkDragEnded)="onDragEnded($event)" cdkDrag>{{movie}}</div>
</div>

Ц компонент

onDragEnded(event: CdkDragEnd) {
  console.log(event)
  event.source.element.nativeElement.style.transform = 'none';
  const source: any = event.source;
  source._passiveTransform = { x: 0, y: 0 };
}

но пока безуспешно.

3 ответа

Решение

Я тоже давно сталкивался с этой проблемой. Наконец я мог это исправить, отправив mouseup событие, которое будет действовать как пользователь, отпустивший мышь.

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.key === 'Escape') {
        document.dispatchEvent(new Event('mouseup'));
    }
}

Это чрезвычайно хакерское решение, которое имеет свои недостатки. На самом деле, вы не отменяете перетаскивание, а просто отбрасываете. Это означает, что если вы зависаете cdkDropList или один активен, это вызовет cdkDropListDropped Emmiter для этого списка. Что-то, что вы можете легко обойти, добавив флаг.

private _canceledByEsq = false;

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.key === 'Escape') {
        this._canceledByEsq = true;
        document.dispatchEvent(new Event('mouseup'));
    }
}

handleDrop() {
    if (!this._canceledByEsq) {
        // Do my data manipulations
    }
}

Надеюсь, это поможет вам...:)

Вы можете переместить перетаскиваемый элемент в позицию, используя:

event['source']['element']['nativeElement']['style']['transform'] = 'translate3d(0,0,0)';
event['source']['_dragRef']['_activeTransform'] = {x: 0, y: 0};
event['source']['_dragRef']['_passiveTransform'] = {x: 0, y: 0};

Лучший способ сделать это - позвонить event.source._dragRef.reset(); (как @AleRubis упомянул в комментарии) на ESCнажатие клавиши. Теперь вопрос в том, откуда вы можете получить этот _dragRef вне событий cdkDrag (ESC ключевое событие), вы можете сохранить его в такой переменной компонента при запуске перетаскивания.

Составная часть:

cdkDragStarted = (event) => { this.dragRef = event.source._dragRef; }

Шаблон:

<p cdkDrag (cdkDragStarted)="cdkDragStarted($event)"> Draggable paragraph </p>

Вот версия с использованием rxjs. Требуется ссылка наCdkDragкак ViewChild. К сожалению, поскольку нет общедоступного метода, чтобы остановить перетаскиваниеDragRef ты должен использовать dispatchEvent как единственный способ завершить процесс перетаскивания.

В приведенном ниже примере есть две части. Что происходит, так это то, что завершенное событие можно прослушать только после начала, и этот экземпляр прослушивания может быть остановлен субъектом, запущенным нажатием escape.

  • В AfterViewInit создается подписка на запущенный EventEmitter изCdkDrag директива.
  • После события запуска поток, который переключается на прослушивание, завершился.
  • Если запрос отмены запущен, поток будет завершен takeUntil оператор и reset() будет вызвана директива для сброса позиции и dispatchEvent() будет использоваться для остановки процесса перетаскивания.
  • В противном случае после запуска конечного события onDragEnded() метод вызывается из OP.
  • Если не происходит чего-то действительно забавного, завершенное событие будет запускаться не более одного раза за запуск, поэтому нет необходимости в дополнительныхtake(1).
private dragCancelRequest = new Subject();

ngAfterViewInit() {
  this.drag.started.pipe(
    switchMap(({ source }) => source.ended.pipe(
      takeUntil(this.dragCancelRequest.pipe(tap(() => {
        source.reset();
        document.dispatchEvent(new Event('mouseup'));
      })))
    )),
    tap(x => this.onDragEnded(x))
  ).subscribe();
}

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
  if (event.key === 'Escape') {
    this.dragCancelRequest.next();
  }
}

Вы можете использовать что-то вроде...

@HostListener('window:keyup', ['$event'])
handleKeyboardEvent(event: KeyboardEvent) {
    if (event.code === 'Escape') {
        // call dragend event
    }
}
Другие вопросы по тегам