Ng2-dragulaでの作業。新しいドロップ注文を使用して、データベース内のすべてのアイテムのorderNumberを更新しようとしています。
dragulaService.dropModel.subscribe((value) => {
var drake = dragulaService.find('bag-orders').drake
var models = drake.models
console.log(models)
})
返される新しいモデルの順序は、バッグ内の順序を反映していません。
TL; DR: ng2-dragulaを使用して、データベースonDrop内で並べ替えを実装している人はいますか?
アイテムをドラッグして(アイテムを非表示にせずに)、dropModelイベントを発生させたい場合:
[dragula]および[dragulaModel]ディレクティブを親要素に配置します。 (たとえば、現在のドキュメントとは異なり、<li>
、あなたはそれらを<ul>
DragularServiceを注入し、コンポーネントのコンストラクターで:
バッグのdragulaService.setOptionsを呼び出します(空の辞書を渡すことができます)。 呼び出さない場合、dropModel
callbackは実行されません
DropModelを購読する
結果:
<!--thecomponent.html-->
<h2>Playlists</h2>
<ul [dragula]='"first-bag"' [dragulaModel]='playlists'>
<li *ngFor="let playlist of playlists">
//Inside the component.ts
playlists: Playlist[];
constructor(private youtubeService: YoutubeService, private dragulaService: DragulaService) {
dragulaService.setOptions('first-bag', {})
dragulaService.dropModel.subscribe((value) => {
this.onDropModel(value);
});
}
private onDropModel(args) {
//Here, this.playlists contains the elements reordered
}
私はng2-dragulaを使用していましたが、私が気づいたことはかなり奇妙です。私が抱えていた問題は同じでした。サーバー呼び出しは、ドラッグされた順序に従ってデータオブジェクトを更新していません。
この問題を解決するために、ngDoCheckライフサイクルフック内のif句を使用しました。
コンソールの印刷オブジェクトでソートされます。さらに掘り下げた後、ネットワークで、更新サーバー呼び出しで送信されたオブジェクトが更新されていないオブジェクトであることがわかりました。
それは、データオブジェクトが更新される前にサーバー呼び出しが行われるためです。
ドラッグを追跡できるグローバル変数を追加するだけで、データオブジェクトが更新されました。
private dropModelUpdated = false;
ngAfterViewInit() {
// this method only changes a variable to execute a method in ngDoCheck
this.dragulaService.drop.subscribe((value) => {
this.dropModelUpdated = true;
});
}
次に、ngDoCheckライフサイクルフックで、
ngDoCheck() {
if (this.dropModelUpdated) { // this excutes if this.dropModelUpdated is true only
const drake = this.dragulaService.find('any_bag_name').drake;
const models = drake.models;
this.modelContent.groups = models[0];
// ...Here... Make the server or DB call to update the model with the changed/sorted order
this.dropModelUpdated = false; // make sure this is there for the next smooth execution
}
}
私は最終的に解決策を見つけました。横リストがあります。最初の2つの要素は無視したいもので、すべてにignore
CSSクラスがあります。そして、すべての要素にはitem
クラスがあります。マークアップ:
<ul [dragula]='"foo-list"' class="list">
<li class="list ignore">a</li>
<li class="list ignore">b</li>
<li class="list" *ngFor="let item of getList()" [attr.data-id]="item.id">{{ item.name }}</li>
</ul>
次に、TypeScript:
constructor(private dragulaService: DragulaService) {
let dragIndex: number, dropIndex: number;
dragulaService.setOptions('foo-list', {
moves: (el, source, handle, sibling) => !el.classList.contains('ignore'),
accepts: (el, target, source, sibling) => sibling === null || !sibling.classList.contains('ignore'),
direction: 'horizontal'
});
dragulaService.drag.subscribe((value) => {
// HACK
let id = Number(value[1].dataset.id);
if (!!id) {
dragIndex = _.findIndex(this.getList(), {id: id});
}
});
dragulaService.drop.subscribe((value:any[]) => {
// HACK
let elementNode = value[2].querySelectorAll('.item:not(.ignore)').item(dragIndex);
if (elementNode) {
let id = Number(elementNode.dataset.id);
if (!!id) {
dropIndex = _.findIndex(this.getList(), {id: id});
}
}
if (value[2] === value[3]) { // target === source
if (dragIndex >= 0 && dropIndex >= 0 && dragIndex !== dropIndex) {
let temp: any = this.list[dragIndex];
this.list[dragIndex] = this.list[dropIndex];
this.list[dropIndex] = temp;
}
}
// Custom code here
});
}
getList(): any[] {
return this.list;
}
Marçalの答えは信じられないほど役に立ち、リストにある各アイテム(私の場合は組織内の連絡先)のシーケンス値を更新するためにDBに更新を投稿するために少し拡張しました:
HTML(コンテナは連絡先の組織です。私の場合、連絡先は組織間で移動できません):
<div class="container" [dragula]="'org-' + org.id" [dragulaModel]="org.contacts">
<nested-contact *ngFor="let contact of org.contacts" [user]="contact" class="contact" [attr.data-id]="contact.id"></nested-contact>
</div>
JS(私の連絡先サービスで、各連絡先に関連付けられている保存されたシーケンス値を更新して、その順序が維持されるようにするPUT関数):
contactsIdPut (id, body) {
let url = '/api/v3/contacts/' + id + '?access_token=' + localStorage.getItem('access_token');
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.put(url, body, options)
.map((response: Response) => {
return response.json();
});
}
JS(私の組織ビューコンポーネントでは、それぞれドラッグアンドドロップ時に実行されるアクションの概要を示します):
export class nestedOrganizationComponent {
orgs = [];
thisOrg: any;
thisContact: any;
constructor (private _contactService: ContactService, private dragulaService: DragulaService) {
this._contactService = _contactService;
let dragIndex: any;
let dropIndex: any;
let elementNode: any;
dragulaService.drag.subscribe((value) => {
let id = Number(value[1].dataset.id);
let orgId: Number = value[0].split('-')[1];
elementNode = value[2].querySelectorAll('.contact:not(.ignore)').item(dragIndex);
if (!!id) {
// this renderedOrgs is just an array to hold the org options that render in this particular view
this._organizationService.renderedOrgs.Push(this.org);
this.thisOrg = this._organizationService.renderedOrgs.filter(org => { return org.id == orgId; })[0];
this.thisContact = this.thisOrg.contacts.filter(contact => { return contact.id == id; })[0];
let arr = this.thisOrg.contacts.map(x => { return x.id; });
dragIndex = arr.indexOf(id);
}
});
dragulaService.drop.subscribe((value: any[]) => {
if (elementNode) {
let id = Number(elementNode.dataset.id);
if (!!id) {
let arr = this.thisOrg.contacts.map(x => { return x.id; });
dropIndex = arr.indexOf(id);
}
}
if (value[2] === value[3]) { // target container === source container
if (dragIndex >= 0 && dropIndex >= 0 && dragIndex !== dropIndex) {
this.thisOrg.contacts.forEach((contact, index) => {
contact.sequence = index;
this.updateSequence(contact.id, index);
});
}
}
});
}
updateSequence (id: Number, index: Number) {
let contactBody = {
avatar: {
sequence: index,
}
};
return this._contactService.contactsIdPut(id, contactBody)
.subscribe(
(data: any) => {
// nothing is needed, the same view can apply because the contact has already been moved.
},
(error: any) => {
console.error(error);
}
);
}
}
うまくいけば、私が今日見つけたのと同じような場所で、他の誰かにこの問題をもう少し明確にしてくれることを願っています。