Angular 7 Drag and Drop - динамически создавайте зоны падения
Есть ли способ динамически создавать зоны сброса? У меня проблемы с ngFor и cdkDropList.
Вот мой первый список и перетаскиваемые элементы:
<div class="subj-container"
cdkDropListOrientation="horizontal"
cdkDropList
#subjectList="cdkDropList"
[cdkDropListData]="subjects"
[cdkDropListConnectedTo]="[lessonList]"
(cdkDropListDropped)="drop($event)"
>
<div class="subject" *ngFor="let subject of subjects" cdkDrag>
{{subject.name}}
</div>
</div>
А вот и мой второй список:
<div class="conta" cdkDropList
#lessonList="cdkDropList"
[cdkDropListData]="appointment.lessons"
[cdkDropListConnectedTo]="[subjectList]"
(cdkDropListDropped)="drop($event)">
<div class="sub" cdkDrag *ngFor="let lesson of appointment.lessons">
{{lesson.name}}
</div>
</div>
Теперь div с классом 'conta' находится внутри * ngFor.
Моя проблема, я полагаю, с моим вторым списком. Если я перетаскиваю элемент из второго списка в список один, он работает нормально, но если я пытаюсь перетащить элемент из списка один в любой экземпляр списка во втором списке, он не может распознать, что элемент перетаскивается. Демо здесь:
Я что-то здесь не так делаю?
Машинописная часть работает нормально.
Спасибо
Ответы
Ответ 1
После целого дня исследований я нашел этот запрос на загрузку репозитория Angular CDK на Github. Теперь, так как я не знал, как интегрировать cdkDropListGroup в мой пример, я решил создать массив идентификаторов, которые будут добавлены в [cdkDropListConnectedTo].
Каждый экземпляр моего второго списка будет генерировать идентификатор, и этот идентификатор будет добавлен в массив с подходящим префиксом (в моем втором списке, в cdkDropList):
<div cdkDropList
[attr.id]="addId(i, j)"
[cdkDropListData]="appointment.lessons"
[cdkDropListConnectedTo]="[subjectList]"
(cdkDropListDropped)="drop($event)"
>
метод addId:
addId(i, j) {
this.LIST_IDS.push('cdk-drop-list-' + i + '' + j);
return i + '' + j;
}
(cdk-drop-list- это префикс ID. CDK помещает этот префикс в каждый элемент с атрибутом cdkDropList)
Итак, мой массив будет выглядеть так:
- CDK-раскрывающегося список-00
- CDK-раскрывающегося список-01
- CDK-раскрывающегося список-02
- и т.п.
Теперь я передаю этот массив [cdkDropListConnectedTo] в моем первом списке:
<div class="subj-container"
cdkDropListOrientation="horizontal"
cdkDropList
#subjectList="cdkDropList"
[cdkDropListData]="subjects"
[cdkDropListConnectedTo]="LIST_IDS"
(cdkDropListDropped)="drop($event)"
>
И это работает без нареканий!
Надеюсь, что это поможет любому с той же проблемой. Кроме того, взгляните на упомянутый выше запрос на получение, мое решение - только обходной путь, возможно, есть лучшее решение с помощью cdkDropListGroup.
Ответ 2
С помощью cdkDropListGroup вы можете сделать следующее:
<div cdkDropListGroup>
<div cdkDropList
[cdkDropListData]="data"
(cdkDropListDropped)="drop($event)">
<div class="row m-2">
<div *ngFor="let i of data cdkDrag>{{i}}</div>
</div>
</div>
<div class="subj-container"
cdkDropListOrientation="horizontal"
cdkDropList
#subjectList="cdkDropList"
[cdkDropListData]="subjects"
(cdkDropListDropped)="drop($event)">
</div>
</div>
Ответ 3
Ссылка на источник
Демо- ссылка
Для Dynamic Drag n Drop Lists мы можем использовать ID вместо # Template переменных
app.component.html
<div class="col-md-3" *ngFor="let week of weeks">
<div class="drag-container">
<div class="section-heading">Week {{week.id}}</div>
<div cdkDropList id="{{week.id}}" [cdkDropListData]="week.weeklist"
[cdkDropListConnectedTo]="connectedTo" class="item-list" (cdkDropListDropped)="drop($event)">
<div class="item-box" *ngFor="let weekItem of week.weeklist" cdkDrag>Week {{week.id}} {{weekItem}}</div>
</div>
</div>
</div>
app.component.ts
import { Component } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
weeks = [];
connectedTo = [];
constructor() {
this.weeks = [
{
id: 'week-1',
weeklist: [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
}, {
id: 'week-2',
weeklist: [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
}, {
id: 'week-3',
weeklist: [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
}, {
id: 'week-4',
weeklist: [
"item 1",
"item 2",
"item 3",
"item 4",
"item 5"
]
},
];
for (let week of this.weeks) {
this.connectedTo.push(week.id);
};
}
drop(event: CdkDragDrop<string[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
}
}
}
Ответ 4
Мне также пришлось столкнуться с этой проблемой. Я попробовал идентификационный подход, но я не чувствовал себя слишком уверенно при использовании. Когда я console.log в этой функции addId(), я вижу один и тот же идентификатор, повторенный несколько раз.
Вместо этого я попытался использовать декоратор @ViewChildren для работы с компонентами cdkList в реальном времени, и он очень хорошо работает для меня.
В машинописи
cdkDropTrackLists: CdkDropList[];
@ViewChildren(CdkDropList)
set cdkDropLists(value: QueryList<CdkDropList>) {
this.cdkDropTrackLists = value.toArray();
}
В шаблоне
<div
cdkDropList
class="track-list"
cdkDropListSortingDisabled
[cdkDropListData]="paragraphIdentifiers"
(cdkDropListDropped)="drop($event)"
[cdkDropListConnectedTo]="cdkDropTrackLists">
</div>
Я думаю, что могу улучшить его, в то время как cdkDropLists как QueryList имеет свойства изменений, которые можно наблюдать.