Last active
March 4, 2021 18:20
-
-
Save federicofazzeri/fa2776915d42b84b0d4d487858cd65d7 to your computer and use it in GitHub Desktop.
Angular 2 state-less directive to add cross device left/right swipe gesture to a UI list
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Directive, HostListener, ElementRef, Output, Input, EventEmitter, AfterContentInit } from '@angular/core'; | |
import { Observable } from 'rxjs/Rx' | |
import 'rxjs/add/observable/fromEvent'; | |
import 'rxjs/add/operator/map'; | |
import 'rxjs/add/operator/filter'; | |
import 'rxjs/add/operator/takeUntil'; | |
import 'rxjs/add/operator/concatMap'; | |
import { Subject } from 'rxjs/Subject'; | |
@Directive({ | |
selector: '[swipeEvent]' | |
}) | |
export class SwipeEventDirective implements AfterContentInit { | |
@Input() swipeWidth; | |
@Output() onSwipeEvent = new EventEmitter(); | |
constructor(private el: ElementRef) { } | |
ngAfterContentInit() { | |
this.moveAndDelete('mousedown', 'mousemove', 'mouseup', 'mouseout'); | |
this.moveAndDelete('touchstart', 'touchmove', 'touchend', 'touchcancel'); | |
} | |
private moveEle = ele => px => ele.style.transform = 'translateX('+ px +'px)'; | |
private resetPos = ele => () => ele.style.transform = 'translateX(0px)'; | |
private emitEvent = px => { | |
if(Math.abs(px) > this.swipeWidth) { | |
this.onSwipeEvent.emit({right: px > 0}); | |
return true; | |
} | |
return false; | |
} | |
private getX = ev => { | |
if(ev.screenX) { | |
return ev.screenX; | |
} else if(ev.touches && ev.touches[0].screenX) { | |
return ev.touches[0].screenX; | |
} | |
return false; | |
} | |
private moveAndDelete = (evStart:string, evMove:string, evEnd:string, evCancel:string) => { | |
const start: Observable<any> = Observable.fromEvent(this.el.nativeElement, evStart); | |
const move: Observable<any> = Observable.fromEvent(this.el.nativeElement, evMove); | |
const end: Observable<any> = Observable.fromEvent(this.el.nativeElement, evEnd); | |
const cancel: Observable<any> = Observable.fromEvent(this.el.nativeElement, evCancel); | |
const moveEle: Function = this.moveEle(this.el.nativeElement.querySelector('.container')); | |
const resetPos = this.resetPos(this.el.nativeElement.querySelector('.container')); | |
const eventEmitted = new Subject<string>(); | |
start | |
.map( ev => this.getX(ev) ) | |
.concatMap( start => | |
move | |
.map(ev => { | |
const delta: number = this.getX(ev) - start; | |
moveEle(delta); | |
if(this.emitEvent(delta)) { | |
eventEmitted.next(); | |
resetPos(); | |
} | |
}) | |
.takeUntil(cancel) | |
.takeUntil(end) | |
.takeUntil(eventEmitted) | |
) | |
.subscribe(); | |
cancel.subscribe(resetPos) | |
end.subscribe(resetPos) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Component } from '@angular/core'; | |
@Component({ | |
template: ` | |
<div> | |
<h2>swipe to delete demo</h2> | |
<ul> | |
<li *ngFor="let item of myList" swipeEvent [swipeWidth]="200" (onSwipeEvent)="swiped($event, item)"> | |
<div class="container"> | |
<div class="text"><span>{{item.text}}</span></div> | |
</div> | |
</li> | |
</ul> | |
</div>`, | |
styles: [` | |
div{width:300px} | |
ul, li { | |
margin: 0; | |
padding: 0; | |
} | |
li { | |
list-style: none; | |
border-radius: 5px; | |
background-color: red; | |
margin-bottom: 10px; | |
} | |
.container { | |
border-radius: 4px; | |
padding:10px; | |
display: flex; | |
background-color: #F1F1F1; | |
} | |
.text { | |
flex: 0 0 90%; | |
display: flex; | |
align-items: center; | |
} | |
button { | |
background-color: #CCC; | |
border-radius: 50%; | |
height: 30px; | |
width: 30px; | |
border: none; | |
margin-right: 10px; | |
} | |
`] | |
}) | |
export class SwipeListComponentDemo { | |
myList = [ | |
{ id: 1, text: 'one'}, | |
{ id: 2, text: 'two'}, | |
{ id: 3, text: 'three'} | |
] | |
constructor() { } | |
swiped(direction, item){ | |
console.log(direction, item); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment