Reputation: 167
Hello my fellow developer. I would like just to ask for help for me to be to achieve the swipe delete feature on our Angular project.
Please see the screenshot below.
This is the code that was given to me to work with that feature.
<div class="col-md-6 col-sm-6 col-xs-12" *ngFor="let relation of bookList" >
<div class="" (click)="selectBookFor(relation)">
<div class="">
<div class="row introMain-wrapper">
<div class="col-auto">
<div class="introImg">
<img src="{{ relation && relation.image }}" alt="user" (error)="setDefaultRelationUserPic($event, relation?.gender)">
</div>
</div>
<div class="col">
<div class="row">
<div class="col"><h5 class="card-title text">{{relation?.firstName}} {{relation?.lastName}}</h5></div>
<div class="col-auto"><span class="relation-text">{{relation?.relationship}}</span></div>
</div>
<h5 class="card-text">{{relation?.email}}</h5>
<div class="outerdiv-text">
<span class="card-text">{{relation?.phone1}}</span>
</div>
</div>
</div>
<div class="line"></div>
</div>
</div>
</div>
I've tried the following plugin:
but it won't work when importing in the submodule and used in component features.Thanks in advance.
Upvotes: 4
Views: 4232
Reputation: 167
Good day fellow developers, thank you for all the answers. By the way, I used https://www.npmjs.com/package/swipe-angular-list as a solution to my problem.
Upvotes: -1
Reputation: 57919
The events touchstart, touchend and touchmove are supported by angular. So you can imagine a directive like:
export interface TouchEventType {
element: TouchDirective;
incrX: number;
incrY: number;
}
@Directive({
selector: '[touch]',
exportAs: 'touch'
})
export class TouchDirective {
origin: any = { x: 0, y: 0 };
style: any = null;
rect: any = { x: 0, y: 0 };
incrX: number = 0;
incrY: number = 0;
@Input('touch') direction: 'horizontal' | 'vertical' | null = null;
@Output() touchMove: EventEmitter<any> = new EventEmitter<any>();
@HostListener('touchstart', ['$event']) touchStart(event) {
this.origin = {
x: event.touches[0].screenX,
y: event.touches[0].screenY
};
}
@HostListener('touchmove', ['$event']) touch(event: TouchEvent) {
this.incrX = this.rect.x + event.touches[0].screenX - this.origin.x;
this.incrY = this.rect.y + event.touches[0].screenY - this.origin.y;
this.style =
this.direction == 'horizontal'
? {
transform: 'translateX(' + this.incrX + 'px)'
}
: this.direction == 'vertical'
? {
transform: 'translateY(' + this.incrY + 'px)'
}
: {
transform: 'translateY(' + this.incrX + 'px,' + this.incrY + 'px)'
};
if (this.direction)
window.scrollBy(this.direction=='horizontal'?
event.touches[0].screenX - this.origin.x:0,
this.direction=='vertical'?
event.touches[0].screenY - this.origin.y:0)
}
@HostListener('touchend', ['$event']) touchEnd() {
this.rect = { y: this.incrY, x: this.incrX };
this.touchMove.emit({
element: this,
incrX: this.incrX,
incrY: this.incrY
});
}
@HostBinding('style') get _() {
return this.style;
}
constructor(private elementRef: ElementRef) {}
reset() {
this.style = null;
this.rect = { x: 0, y: 0 };
}
}
You can use in an .html like
<ng-container *ngFor="let item of array;let i=index">
<p touch='horizontal' (touchMove)="touchmove($event,i)">
Start editing to see some magic happen {{item}}
</p>
</ng-container>
array:any[]=[1,2,3,4,5,6,7]
touchmove(event:TouchEventType,index:number)
{
if (event.incrX<-10) //10px to the left
this.array.splice(index,1)
else
event.element.reset()
}
See the stackblitz without any warranty
Update If we want that work in touched and no touched screen we can take another approach. Instead of use @HostListener
we can use fromEvent
rxjs operator. (else we need make a hostListenr over mousedown,mouseup and mousemove)
To control at time the touch events and mouse events we use rxjs merge operator, that received the value from the two observables. To use exact the same code, we use "map" in the touch events to convert the respose (a TouchEvent) in a MouseEvent.
The last point is use the "tap" to know if is a touchscreen or not. In a touch screen if we swipe down/up, we need scroll the window dwon/up is oure directive only allow horizontal movements
@Directive({
selector: '[touch]',
exportAs: 'touch'
})
export class TouchDirective {
origin: any = { x: 0, y: 0 };
style: any = null;
rect: any = { x: 0, y: 0 };
incrX: number = 0;
incrY: number = 0;
onDrag:boolean=false;
isTouched:boolean=false;
moveSubscription: any;
downSubscription: any;
@Input('touch') direction: 'horizontal' | 'vertical' | null = null;
@Output() touchMove: EventEmitter<any> = new EventEmitter<any>();
@HostBinding('style') get _() {
return this.style;
}
@HostBinding('class.no-select') get __() {
return this.onDrag;
}
constructor(private elementRef: ElementRef) {}
ngOnInit() {
this.downSubscription=merge(
fromEvent(this.elementRef.nativeElement, 'mousedown').pipe(tap(_=>this.isTouched=false)),
fromEvent(this.elementRef.nativeElement, 'touchstart').pipe(tap(_=>this.isTouched=true),
map((event: TouchEvent) => ({
target: event.target,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY
}))
)
).subscribe((event: MouseEvent) => {
//see that is the same code that @HostListener('touchstart', ['$event'])
this.origin = {
x: event.screenX,
y: event.screenY
};
this.onDrag=true;
merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend'))
.pipe(take(1))
.subscribe(() => {
//see that is the same code that @HostListener('touchend', ['$event'])
if (this.moveSubscription) {
this.moveSubscription.unsubscribe();
this.moveSubscription = undefined;
}
this.rect = { y: this.incrY, x: this.incrX };
this.touchMove.emit({
element: this,
incrX: this.incrX,
incrY: this.incrY
});
this.onDrag=false;
});
if (!this.moveSubscription) {
this.moveSubscription = merge(
fromEvent(document, 'mousemove'),
fromEvent(document, 'touchmove').pipe(
map((event: TouchEvent) => ({
target: event.target,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY
}))
))
.subscribe((event: MouseEvent) => {
//see that is the same code that @HostListener('touchmove', ['$event'])
this.incrX = this.rect.x + event.screenX - this.origin.x;
this.incrY = this.rect.y + event.screenY - this.origin.y;
this.style =
this.direction == 'horizontal'
? {
transform: 'translateX(' + this.incrX + 'px)'
}
: this.direction == 'vertical'
? {
transform: 'translateY(' + this.incrY + 'px)'
}
: {
transform: 'translateY(' + this.incrX + 'px,' + this.incrY + 'px)'
};
if (this.direction && this.isTouched)
window.scrollBy(
this.direction == 'horizontal'
? event.screenX - this.origin.x
: 0,
this.direction == 'vertical'
? event.screenY - this.origin.y
: 0
);
})
}
});
}
ngOnDestroy() {
this.downSubscription.unsubscribe();
}
reset() {
this.style = null;
this.rect = { x: 0, y: 0 };
}
}
we add the class
.no-select {
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
in styles.css and
@HostBinding('class.no-select') get __() {
return this.onDrag;
}
To not select when the element is swipping
The stackblitz for touch/no touch screen
Upvotes: 1
Reputation: 683
You can use Angular material Drag and Drop https://material.angular.io/cdk/drag-drop/examples
From that, you can create a swipe delete option.
Demo
<div class="container">
<div class="row">
<div
cdkDropList
cdkDropListSortingDisabled
[cdkDropListData]="bookList"
class="example-list"
(cdkDropListDropped)="drop($event)">
<div class="example-box" *ngFor="let item of bookList;let i= index" cdkDrag>{{item.firstName}}</div>
</div>
</div>
</div>
TS
drop(event: CdkDragDrop<any, any>): any {
this.bookList.splice(event.currentIndex, 1);
}
Upvotes: 3