Reputation: 9151
I'm trying to capture swipe gestures on the entire screen of my application. The idea is to have these dispatch actions that other services can listen to, in this case a router for navigation purposes.
Because I only want these listeners in one place I tried attaching them to the body or to a div covering the screen of my app. Both methods don't work as I want.
<div (swipeleft)="swipeLeft()" (swiperight)="swipeRight()" class="touch"></div>
swipeLeft() {
this.store.dispatch(UserActions.swipeLeft());
}
The problem with a touch layer should have been obvious in retrospect: it covers the screen and thus the rest of the app. Setting pointer-events: none;
to reach the rest of the app breaks the swipe detection.
const mc = new Hammer(document.querySelector('body'));
mc.on('swipeleft swiperight', (ev) => {
console.log(ev.type);
// this.store.dispatch(UserActions.swipeLeft());
});
The problem with attaching it here is that it only seems to register swipes on certain elements like app-root
and a status-bar that I have but not on my router-outlet nor a toolbar in the bottom that holds some buttons.
So, how do I capture swipes on my entire application?
I've tried to create a snippet to reproduce the problem, but without Angular components it pretty much behaves as I hoped my app would. Similar behavior as my problem can be observed though when trying to swipe from around the button margins in the snippet.
const touchLayer = document.getElementById('touch');
const body = document.querySelector('body');
const mc = new Hammer(body);
mc.on("swipeleft swiperight", function(ev) {
touchLayer.textContent = ev.type + " gesture detected.";
});
#touch,
#myApp {
position: fixed;
height: 300px;
width: 100%;
}
#myApp {
background: repeating-linear-gradient(-55deg, #666, #666 10px, #333 10px, #333 20px);
opacity: .5;
}
#touch {
background: cyan;
text-align: center;
font: 30px/300px Helvetica, Arial, sans-serif;
opacity: .5;
}
.card {
width: 200px;
height: 100px;
background: red;
position: relative;
margin: 1em;
}
button {
margin: 2em;
right: 0;
bottom: 0;
position: absolute;
}
<script src="https://hammerjs.github.io/dist/hammer.js"></script>
<!-- Tried putting this on top, blocking the screen -->
<div id="touch"></div>
<div id="myApp">
<div class="card">
<button onclick="alert('test')">Button!</button>
</div>
<div class="card">
<button onclick="alert('test')">Button!</button>
</div>
</div>
Upvotes: 1
Views: 8018
Reputation: 57939
When you want to add Hammer to an Angular 8 application, you need as provider HAMMER_GESTURE_CONFIG and use class HammerGestureConfig
providers: [
{
provide: HAMMER_GESTURE_CONFIG,
useClass: HammerGestureConfig
}
]
Well, if you want use another class thar override some propertie -e.g. you want to swipe in all direction-, you create a class that extends HammerGestureConfig and use this class in the provider
export class MyHammerConfig extends HammerGestureConfig {
overrides = <any>{
swipe: { direction: Hammer.DIRECTION_ALL }
};
}
// And use as provider
providers: [
{
provide: HAMMER_GESTURE_CONFIG,
useClass: MyHammerConfig
}
]
In your app, you can use fromEvent rxjs
const hammerConfig = new HammerGestureConfig()
//or if you use another class as provider:
// const hammerConfig=new MyHammerConfig()
const hammer=hammerConfig.buildHammer(document.documentElement)
fromEvent(hammer, "swipe").pipe(
takeWhile(()=>this.alive))
.subscribe((res: any) => {
console.log(res.deltaX);
});
see an example in stackblitz
(*)I put a pipe takeWhile to remark the necesary unsubscribe
Upvotes: 3