我有一个循环中的项目列表。
<div *ngFor="let item of items; let i=index">
<item-detail [item]="item" [dragula]='"first-bag"' [dragulaModel]='myItems' id="{{item.id}}" position={{i}}></item-detail>
</div>
我想要的输出是,当用户将一个项目拖放到另一个位置时,一个API调用将被执行,新的订单将被保存在我的数据库中。
为了做到这一点,我需要项目ID和新位置。位置必须是1到6之间的一个数字(基于用户拖动项目的位置…)
到目前为止我所做的是下面的方法:
private onDrop(args) {
let [e, el] = args;
console.log(el.id)
console.log(el.position)
}
但是ID和位置不能正常工作…我相信有一种更容易、更简单、更正确的方法来做到这一点。
任何想法?
你需要像这样移动你的dragula指令到你的项目的父容器中:
<div class="container" [dragula]='"bag-one"' [dragulaModel]='items'>
<div [attr.id]="item.id" [attr.title]="i" class="card-item" *ngFor="let item of items; let i=index">
<item-detail></item-detail>
</div>
</div>
在yourComponent.ts let [el, target, source] = args;
console.log(el.id);
console.log(el.title);
你也可以在Item-Detail组件中使用@Input来输入所需的id和位置。
<item-detail [iteminfo]="item"></item-detail>
在你的Component.ts
Import {Component, Input} from '@angular/core';
@Component({....});
@Input() iteminfo: Item;
这是我在我的项目中所做的。对于父组件:
import { Component, Input } from '@angular/core';
import { Card } from '../model/card';
import { Item } from '../model/item';
import { dragula, DragulaService } from 'ng2-dragula/ng2-dragula';
@Component({
selector: 'card', //parent component for item component
template: `
<div class="items"[dragula]='"bag-one"' [dragulaModel]='card.items'>
<div class="card-item" *ngFor="let item of card.items; let i = index; trackBy item?.item_Id">
<item [item]="item" [index]="i"></item>
</div>
</div>
})
export class CardComponent {
constructor(private dragulaService: DragulaService)
{
dragulaService.setOptions('bag-one', {
revertOnSpill: true
});
dragulaService.drop.subscribe((value) => {
this.onDrop(value.slice(1));
});
}
}
对于Item组件:
import { Component, Input } from '@angular/core';
import { Item } from '../model/item';
@Component({
selector: 'item',
template: `
{{item.title}} {{index}}
`
})
export class ItemComponent implements OnInit {
constructor(private itemSvc:ItemService) {}
private _index: number;
@Input()item: Item;
@Input()
set index(i: number) {
this._index = i;
// Do something here like save to database.
console.log('item index changed: ', this.item.title + i);
}
// Getter for the index Input property
get index(): number{
return this._index;
}
}
最后注释:参见angular的"拦截输入属性改变的setter"。在CookBook -> Components Interaction下的web站点https://angular.io/docs/ts/latest/cookbook/
我知道这是很久以前的事了…但是我非常努力地解决了类似的问题,希望其他人能从我的发现中受益:
我的html:
<tbody [dragula]='"bag-one"' [dragulaModel]="currentWorkingData" #bag1>
<tr *ngFor="let faq of currentWorkingData; let i = index;" class="faq" [attr.data-id]="faq.id" [attr.data-index]="i" [attr.data-title]="faq.title" [attr.data-description]="faq.description">
<td>
<span>{{ faq.title }}</span>
</td>
<td>
<button (click)="removeFaq(faq)" class="btn btn-xs btn-danger">Remove</button>
<br />
<button (click)="editFaq(faq)" class="btn btn-xs btn-info">Edit</button>
</td>
</tr>
</tbody>
在我的组件(typescript)中,我有以下内容:
export class CategoriesComponent {
categoryList: any = [];
url: string = '';
updatedCategory: any = [];
constructor(private apiService: ApiService, private dragulaService: DragulaService) {
let currentCategory = this.categoryList;
this.url = apiService.urls.categories;
apiService.get(apiService.urls.categories).subscribe(
data => this.loadCategories(data),
err => this.loadCategories('err'));
dragulaService.setOptions('bag-one', {
revertOnSpill: true
});
dragulaService.drag.subscribe((value: any) => {
let currentCategory = this.categoryList; //onchage event ---> pushing data through
});
dragulaService.drop.subscribe((value: any[]) => { //runs when item being dragged is dropped into new location
let currentCategory = this.categoryList; // --> pushing the data through
const [bagName, e, el] = value;
this.onDrop(value.slice(1)); // --> passing to onDrop
});
}
private onDrop(args: any) {
let [el, target, source] = args;
const rowData = Array.from(target.children);
this.updatedCategory = rowData.map((row: any, index: number) => {
return {
id: row.dataset.id,
name: row.dataset.name,
sideBar: row.dataset.sidebar,
index
}
});
return new Promise((resolve: any, reject: any) => {
this.handleSaveRequest();
});
}
loadCategories(res:any) {
if(res === 'err'){
swal('Ooops!', 'Something went wrong, prease try again.', 'error');
} else {
console.log(res); //returns the current (correct) array
for (let i = 0; i < res.categories.length; i++) {
this.categoryList.push({
id: res.categories[i].id,
value: res.categories[i].name,
sideBar: res.categories[i].sideBar,
index: res.categories[i].index
});
}
}
}
第一次运行该命令时,必须手动将索引号循环到其中,以便它有一个初始值(或者在保存到数据库时设置它)。
然后,当你拖放一些东西^^^的ondrop方法将运行一个handleSave方法也在同一个组件(typescript)…对于我来说,我循环遍历页面上的当前值。我认为这真的是最好的方式,因为你可以一次完成几件事(虽然,我不是javascript专家):
handleSaveRequest(): Promise < any > {
const listCatArrange = this.updatedCategory;
const { name, sideBar, id, index } = this.categoryList;
let side_bar = sideBar;
const bodyCL = { name, side_bar, index };
return new Promise((resolve: any, reject: any) => {
let i = 0;
let processRequest = () => {
if(i < listCatArrange.length){
let bodyList = {
name: listCatArrange[i].name,
sideBar: listCatArrange[i].sideBar,
index: listCatArrange[i].index
};
let url = this.apiService.urls.categories;
let curId = listCatArrange[i].id;
this.apiService.patch(url + `/${curId}`, bodyList).subscribe(
data => processRequest(),
err => resolve('err'),
);
i++;
processRequest();
} else{
resolve(true);
}
};
processRequest();
});
}
我希望这有助于那里的人。我和一个朋友花了很长很长时间才弄明白。关于如何做这样的事情,绝对没有很多关于dragula的文档。