CdkDragDrop и ngTemplateOutlet
Я пытаюсь использовать функции Drag&Drop, связанные с Angular Material 7.
Я разделил свой шаблон на многоразовые кусочки, используя ngTemplateOutlet
и каждый вариант может быть либо Thing™, либо вложенным Thing™, в котором есть еще несколько суб-вещей™.
Nested Things™ отображаются в виде панели расширения. Я хочу, чтобы все вещи первого уровня были переупорядочены, как если бы они были списком.
(Хорошо, хорошо, очевидно, что это переставляемый sidenav с обычными и вложенными параметрами, просто притворитесь, что это не так очевидно)
Это код, который я изначально написал.
<div cdkDropList (cdkDropListDropped)="dropItem($event)" lockAxis="y">
<ng-container *ngFor="let thing of things">
<ng-container
*ngTemplateOutlet="!thing.children ? singleThing : multipleThing; context: { $implicit: thing }"
></ng-container>
</ng-container>
</div>
<ng-template #singleThing let-thing>
<div cdkDrag>
<ng-container *ngTemplateOutlet="thingTemplate; context: { $implicit: thing }"></ng-container>
</div>
</ng-template>
<ng-template #multipleOption let-thing>
<mat-expansion-panel cdkDrag (cdkDropListDropped)="dropItem($event)">
<mat-expansion-panel-header>
<mat-panel-title>
<p>Nested thing title</p>
<span cdkDragHandle></span>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-container *ngFor="let childThing of thing.children">
<div class="childThing">
<ng-container *ngTemplateOutlet="thingTemplate; context: { $implicit: childThing }"></ng-container>
</div>
</ng-container>
</mat-expansion-panel>
</ng-template>
<ng-template #thingTemplate let-thing>
<p>I'm a thing!</p>
<span cdkDragHandle></span>
</ng-template>
Проблема: отдельные вещи можно перетаскивать, но они не приводятся в исполнение, как список, как должен делать cdkDropList, я могу просто перетаскивать их повсюду.
У меня была похожая проблема некоторое время назад при попытке использовать шаблоны розеток и положить ng-template
Вернувшись к "потоку HTML", я решил эту проблему.
<div cdkDropList (cdkDropListDropped)="dropItem($event)" lockAxis="y">
<ng-container *ngFor="let thing of things">
<ng-container
*ngIf="!thing.children; then singleThing; else multipleThing"
></ng-container>
<ng-template #singleThing>
<div cdkDrag>
<ng-container *ngTemplateOutlet="thingTemplate; context: { $implicit: thing }"></ng-container>
</div>
</ng-template>
<ng-template #multipleOption>
<mat-expansion-panel cdkDrag (cdkDropListDropped)="dropItem($event)">
<mat-expansion-panel-header>
<mat-panel-title>
<p>Nested thing title</p>
<span cdkDragHandle></span>
</mat-panel-title>
</mat-expansion-panel-header>
<ng-container *ngFor="let childThing of thing.children">
<div class="childThing">
<ng-container *ngTemplateOutlet="thingTemplate; context: { $implicit: childThing }"></ng-container>
</div>
</ng-container>
</mat-expansion-panel>
</ng-template>
</ng-container>
</div>
<ng-template #thingTemplate let-thing>
<p>I'm a thing!</p>
<span cdkDragHandle></span>
</ng-template>
И, конечно, почему бы и нет, это работает! Да, хорошо, но почему?
Не сильно изменился, мы использовали ngIf
вместо первого ngTemplateOutlet
и удалил привязки контекста для Thing™, потому что теперь у обоих шаблонов есть ссылка на локальную переменную благодаря общей области.
Так почему же он работает вторым способом, а не первым?
Бонусы: возможно ли заставить его работать, сохраняя первую структуру кода, которая, на мой взгляд, кажется более читаемой и чистой?
0 ответов
У меня была такая же проблема, я даже сообщал об этом как о проблеме на GitHub.
Оказывается, это вызвано обособленностью cdkDropList
от cdkDrag
, cdkDrag
должен быть в теге, вложенном в cdkDropList
иначе перетаскиваемый элемент не обнаружит зону сброса.
Решение в вашем случае будет дополнительным <div cdkDrag>
ниже cdkDropList
и только при этом вы бы назвали шаблон с ngTemplateOutlet
,