问题
I have a Trello-like web app. with Task
s that can be dragged & dropped in status boxes (To do, ogoing and done). I use ng2-dragula to achieve the drag & drop feature and wanted to implement a way to filter my tasks with an Angular 2
pipe.
So I did, by first defining my pipe:
@Pipe({
name: 'taskFilter',
pure: false
})
export class TaskFilterPipe implements PipeTransform {
transform(items: Task[], filter: Task): Task[] {
if (!items || !filter) {
return items;
}
// pipes items array, items which match and return true will be kept, false will be filtered out
return items.filter((item: Task) => this.applyFilter(item, filter));
}
applyFilter(task: Task, filter: Task): boolean {
for (const field in filter) {
if (filter[field]) {
if (typeof filter[field] === 'string') {
if (task[field].toLowerCase().indexOf(filter[field].toLowerCase()) === -1) {
return false;
}
}
}
}
return true;
}
}
And adding it to my *ngFor
:
<!-- For every different status we have, display a card with its tasks -->
<md-grid-tile *ngFor="let istatus of status">
<!-- Display every task in our array and pipe in the filter -->
<div *ngFor="let task of tasks | taskFilter:projectService.filteredTask">
<!-- Check if said task has the right status and display it -->
<md-card class="task-card" *ngIf="task.status == istatus" (click)="openDetails(task)">
{{task.title}}
</md-card>
</div>
</md-grid-tile>
It works, yay ! But when I drag & drop any task, it simply disappears, never to be found again.
It seems that changing a task's status in any way is making it disappear, how can that be related to my pipe?
Is there a way to use both dragula and Angular 2 pipes?
回答1:
It's not because of your pipe. I faced this problem and it's CSS related.
Put this into a global style sheet (and of course, style it to your needs) :
// Dragula styling for the drag n' drop
.gu-mirror {
font-weight: 500;
padding: 8px;
cursor: grabbing;
position: fixed;
margin: 0;
z-index: 9999;
opacity: .8;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
filter: alpha(opacity=80)
}
.gu-hide {
display: none!important
}
.gu-unselectable {
-webkit-user-select: none!important;
-moz-user-select: none!important;
-ms-user-select: none!important;
user-select: none!important
}
.gu-transit {
opacity: .2;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
filter: alpha(opacity=20)
}
回答2:
In order for your pipe to work, you need to declare 'dragulaModels' on your dragula bags elements. The way you do it now, on drag&drop you only move your generated div into DOM without updating your model, thus your pipe will never work since your array of task never get updated on drop.
Here is a working example to give you guidance:
html
<div [dragula]='"first-bag"' [dragulaModel]="groupA.items">
<div *ngFor='let item of groupA.items | filter:"C"' [innerHtml]='item.name'></div>
</div>
<div [dragula]='"first-bag"' [dragulaModel]="groupB.items">
<div *ngFor='let item of groupB.items' [innerHtml]='item.name'></div>
</div>
component
import { Component } from '@angular/core';
import { dragula, DragulaService } from 'ng2-dragula/ng2-dragula';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
groupA: any = {
name: 'Group A',
items: [{ name: 'Item A' }, { name: 'Item B' }, { name: 'Item C' }, { name: 'Item D' }]
};
groupB: any = {
name: 'Group B',
items: [{ name: 'Item 1' }, { name: 'Item 2C' }, { name: 'Item 3' }, { name: 'Item 4' }]
};
}
pipe
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'filter',
pure: false
})
export class FilterPipe implements PipeTransform {
transform(items: Array<any>, filter: string): any {
if (!items || !filter) {
return items;
}
return items.filter(item => {
for (const field in item) {
if (item[field] === null || item[field] === undefined) {
continue;
}
if (item[field].toString().toLowerCase().indexOf(filter.toLowerCase()) !== -1) {
return true;
}
}
return false;
}
);
}
}
When you drag&drop elements from groupB to groupA, it will move your elements from one array to the other and filter your first array (in this case you will only display the items containing a 'c' on the first array).
Added a demo app Angular2+-demo-app-dragula-pipe
回答3:
You are missing your binding between display and business logic from the piece of code you posted. Dragula needs to know what needs to be updated after you drag anything. [dragulaModel] is pointing to your array, [dragula] to the name of your bag/ drake.
<md-grid-tile *ngFor="let istatus of status" [dragula]="'task-bag'" [dragulaModel]="tasks">
See docu: https://github.com/valor-software/ng2-dragula
来源:https://stackoverflow.com/questions/44820056/using-angular2-pipes-with-dragula-on-an-array