如何使用带有预定义插槽的 Angular CDK DragDrop?
How to use Angular CDK DragDrop with predefined slots?
StackBlitz:https://stackblitz.com/edit/league-predictions
我有一个项目,我想预测足球联赛的排名。我有两个列表,一个包含预测,另一个包含所有团队。
一开始预测列表是空的,所以可以开始拖入队伍。但是因为是空的,所以第一队自动排在第一位。当然你可以稍后对它们进行排序,但我想要的是基于团队数量的预定义插槽。这样你就可以直接把队伍拖到合适的地方了。
我真的无法在 Internet 上找到有关如何实现此目的的解决方案。
这是我目前的情况,所以你可以看到我在说什么:
League Predictions
这就是我想要实现的。
有人知道如何为 Angular CDK DragDrop
预定义插槽吗
这是我当前的代码。
<div class="container">
<div class="example-container">
<h5>Predictions</h5>
<div
cdkDropList
#predictionsList="cdkDropList"
[cdkDropListData]="predictions"
[cdkDropListConnectedTo]="[teamList]"
class="example-list"
(cdkDropListDropped)="drop($event)"
>
<div class="example-box" *ngFor="let prediction of predictions; let i = index" cdkDrag>
<app-team [team]="prediction" [index]="i"></app-team>
</div>
</div>
</div>
<div class="example-container">
<h5>Teams</h5>
<div
cdkDropList
#teamList="cdkDropList"
[cdkDropListData]="teams"
[cdkDropListConnectedTo]="[predictionsList]"
class="example-list"
(cdkDropListDropped)="drop($event)"
>
<div class="example-box" *ngFor="let team of teams;" cdkDrag>
<app-team [team]="team"></app-team>
</div>
</div>
</div>
</div>
不要介意长长的队伍名单,这都是数据库中的数据
import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
predictions = [
];
teams = [
{
name: 'ADO Den Haag',
logo: 'Ado-Den-Haag-Logo.png'
},
{
name: 'Ajax',
logo: 'AFC-Ajax-Logo.png'
},
{
name: 'AZ',
logo: 'AZ-Alkmaar-Logo.png'
},
{
name: 'FC Emmen',
logo: 'FC-Emmen-Logo.png'
},
{
name: 'FC Groningen',
logo: 'FC-Groningen-Logo.png'
},
{
name: 'FC Twente',
logo: 'fc-twente-logo.png'
},
{
name: 'FC Utrecht',
logo: 'FC-Utrecht-Logo.png'
},
{
name: 'Feyenoord',
logo: 'Feyenoord-Rotterdam-Logo.png'
},
{
name: 'Fortuna Sittard',
logo: 'Fortuna-Sittard-Logo.png'
},
{
name: 'Heracles',
logo: 'Heracles-Almelo-Logo.png'
},
{
name: 'PEC Zwolle',
logo: 'PEC-Zwolle-Logo.png'
},
{
name: 'PSV',
logo: 'PSV-Eindhoven-Logo.png'
},
{
name: 'RKC Waalwijk',
logo: 'rkc-waalwijk.png'
},
{
name: 'SC Heerenveen',
logo: 'SC-Heerenveen-Logo.png'
},
{
name: 'Sparta Rotterdam',
logo: 'Sparta_Rotterdam_logo.png'
},
{
name: 'Vitesse',
logo: 'Vitesse-Arnhem-Logo.png'
},
{
name: 'VVV Venlo',
logo: 'VVV-Venlo-Logo.png'
},
{
name: 'Willem II',
logo: 'Willem-II-Logo.png'
},
];
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);
}
}
}
好吧,如果没有有效的 stackblitz,很难提供任何有用的代码示例,但我试一试。
对于左侧列表,我将创建一个包含空对象的数组,其大小与您的团队列表相同。
我会创建 {name: null, logo: null}
个条目并在模板中检查以不显示任何内容 if name === null
扩展 drop
事件处理程序并添加检查 if (dropTarget.name === null)
并将虚拟条目替换为您的值。否则保持你现有的逻辑
编辑:基本 Stackblitz 示例:Stackblitz
做了一个 stackblitz 概述了要做什么,首先,在你的预测数组中创建虚拟条目:
getPrediction(): Team[] {
let localStorageItem = JSON.parse(localStorage.getItem(this.league.name));
return localStorageItem == null ? this.getTeams().map(t => ({})) : localStorageItem.standings;
}
这将填补您的位置。禁止拖动这些项目:
<div class="example-box" *ngFor="let prediction of predictions; let i = index" cdkDrag [cdkDragDisabled]="!prediction.name">
接下来,您需要向 drop
函数添加一个参数,以了解哪个容器被放置在上面:
drop(event: CdkDragDrop<Team[]>, droppedOn: 'teams' | 'predictions') {
并适当更新模板:
(cdkDropListDropped)="drop($event, 'predictions')"
...
(cdkDropListDropped)="drop($event, 'teams')"
在您的 drop 函数中,您在列表传输的情况下使用此参数来添加或删除占位符:
if (droppedOn === 'teams') {
// moved back to teams, need to re add placeholder
this.predictions.push({});
} else {
// otherwise, removing a placeholder
// find the idx to remove, first placeholder at or below current idx
let removeIdx = this.predictions.findIndex((t, i) => i >= event.currentIndex && !t.name);
if (removeIdx < 0) {
// or just the first available.
removeIdx = this.predictions.findIndex(t => !t.name);
}
this.predictions.splice(removeIdx, 1);
}
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
也许可以对算法进行一些调整/改进,以确定在将团队从团队中删除时删除哪个空白,或者在切换回团队时在何处插入空白,但这里的简单版本有效我玩的时候还不错
StackBlitz:https://stackblitz.com/edit/league-predictions
我有一个项目,我想预测足球联赛的排名。我有两个列表,一个包含预测,另一个包含所有团队。
一开始预测列表是空的,所以可以开始拖入队伍。但是因为是空的,所以第一队自动排在第一位。当然你可以稍后对它们进行排序,但我想要的是基于团队数量的预定义插槽。这样你就可以直接把队伍拖到合适的地方了。
我真的无法在 Internet 上找到有关如何实现此目的的解决方案。
这是我目前的情况,所以你可以看到我在说什么: League Predictions
这就是我想要实现的。
有人知道如何为 Angular CDK DragDrop
预定义插槽吗这是我当前的代码。
<div class="container">
<div class="example-container">
<h5>Predictions</h5>
<div
cdkDropList
#predictionsList="cdkDropList"
[cdkDropListData]="predictions"
[cdkDropListConnectedTo]="[teamList]"
class="example-list"
(cdkDropListDropped)="drop($event)"
>
<div class="example-box" *ngFor="let prediction of predictions; let i = index" cdkDrag>
<app-team [team]="prediction" [index]="i"></app-team>
</div>
</div>
</div>
<div class="example-container">
<h5>Teams</h5>
<div
cdkDropList
#teamList="cdkDropList"
[cdkDropListData]="teams"
[cdkDropListConnectedTo]="[predictionsList]"
class="example-list"
(cdkDropListDropped)="drop($event)"
>
<div class="example-box" *ngFor="let team of teams;" cdkDrag>
<app-team [team]="team"></app-team>
</div>
</div>
</div>
</div>
不要介意长长的队伍名单,这都是数据库中的数据
import { Component, OnInit, ElementRef, ViewChild } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
predictions = [
];
teams = [
{
name: 'ADO Den Haag',
logo: 'Ado-Den-Haag-Logo.png'
},
{
name: 'Ajax',
logo: 'AFC-Ajax-Logo.png'
},
{
name: 'AZ',
logo: 'AZ-Alkmaar-Logo.png'
},
{
name: 'FC Emmen',
logo: 'FC-Emmen-Logo.png'
},
{
name: 'FC Groningen',
logo: 'FC-Groningen-Logo.png'
},
{
name: 'FC Twente',
logo: 'fc-twente-logo.png'
},
{
name: 'FC Utrecht',
logo: 'FC-Utrecht-Logo.png'
},
{
name: 'Feyenoord',
logo: 'Feyenoord-Rotterdam-Logo.png'
},
{
name: 'Fortuna Sittard',
logo: 'Fortuna-Sittard-Logo.png'
},
{
name: 'Heracles',
logo: 'Heracles-Almelo-Logo.png'
},
{
name: 'PEC Zwolle',
logo: 'PEC-Zwolle-Logo.png'
},
{
name: 'PSV',
logo: 'PSV-Eindhoven-Logo.png'
},
{
name: 'RKC Waalwijk',
logo: 'rkc-waalwijk.png'
},
{
name: 'SC Heerenveen',
logo: 'SC-Heerenveen-Logo.png'
},
{
name: 'Sparta Rotterdam',
logo: 'Sparta_Rotterdam_logo.png'
},
{
name: 'Vitesse',
logo: 'Vitesse-Arnhem-Logo.png'
},
{
name: 'VVV Venlo',
logo: 'VVV-Venlo-Logo.png'
},
{
name: 'Willem II',
logo: 'Willem-II-Logo.png'
},
];
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);
}
}
}
好吧,如果没有有效的 stackblitz,很难提供任何有用的代码示例,但我试一试。
对于左侧列表,我将创建一个包含空对象的数组,其大小与您的团队列表相同。
我会创建 {name: null, logo: null}
个条目并在模板中检查以不显示任何内容 if name === null
扩展 drop
事件处理程序并添加检查 if (dropTarget.name === null)
并将虚拟条目替换为您的值。否则保持你现有的逻辑
编辑:基本 Stackblitz 示例:Stackblitz
做了一个 stackblitz 概述了要做什么,首先,在你的预测数组中创建虚拟条目:
getPrediction(): Team[] {
let localStorageItem = JSON.parse(localStorage.getItem(this.league.name));
return localStorageItem == null ? this.getTeams().map(t => ({})) : localStorageItem.standings;
}
这将填补您的位置。禁止拖动这些项目:
<div class="example-box" *ngFor="let prediction of predictions; let i = index" cdkDrag [cdkDragDisabled]="!prediction.name">
接下来,您需要向 drop
函数添加一个参数,以了解哪个容器被放置在上面:
drop(event: CdkDragDrop<Team[]>, droppedOn: 'teams' | 'predictions') {
并适当更新模板:
(cdkDropListDropped)="drop($event, 'predictions')"
...
(cdkDropListDropped)="drop($event, 'teams')"
在您的 drop 函数中,您在列表传输的情况下使用此参数来添加或删除占位符:
if (droppedOn === 'teams') {
// moved back to teams, need to re add placeholder
this.predictions.push({});
} else {
// otherwise, removing a placeholder
// find the idx to remove, first placeholder at or below current idx
let removeIdx = this.predictions.findIndex((t, i) => i >= event.currentIndex && !t.name);
if (removeIdx < 0) {
// or just the first available.
removeIdx = this.predictions.findIndex(t => !t.name);
}
this.predictions.splice(removeIdx, 1);
}
transferArrayItem(event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex);
也许可以对算法进行一些调整/改进,以确定在将团队从团队中删除时删除哪个空白,或者在切换回团队时在何处插入空白,但这里的简单版本有效我玩的时候还不错