Reputation: 5374
I'm trying to build a custom toggle in Angular. Everything works as expected on desktop but not on mobile. So I click and I drag to the right. This is how it is supposed to work on desktop, on mobile I need to tap and slide on the right. This doesn't work.
I have a live example here codesandbox.
What am I doing wrong?
import { Component, ViewChild, ElementRef, Renderer2 } from "@angular/core";
@Component({
selector: "app-root",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
@ViewChild("theSlider") theSlider: ElementRef;
@ViewChild("lock") theLock: ElementRef;
@ViewChild("banText") banText: ElementRef;
@ViewChild("timerText") timerText: ElementRef;
myPos = 0;
posX = 0;
borderLeft = 2;
borderRight = 62;
wasSlide = 0;
easing = 0;
step = 0;
duration = 30;
repeater;
mousemoveUnlistener;
mouseupUnlistener;
touchstartUnlistener;
touchendUnlistener;
constructor(private renderer: Renderer2) {}
sliderDown(e) {
if (e.cancelable) {
e.preventDefault();
e.stopPropagation();
e = e || window.event;
this.posX = e.clientX;
if (this.wasSlide !== 2) {
this.wasSlide = 1;
}
this.mousemoveUnlistener = this.renderer.listen(
"document",
"mousemove",
(evt) => {
this.dragSlider(evt);
}
);
this.mouseupUnlistener = this.renderer.listen(
"document",
"mouseup",
(evt) => {
this.closeDrag();
}
);
this.touchstartUnlistener = this.renderer.listen(
"document",
"touchstart",
(evt) => {
this.dragSlider(evt);
}
);
this.touchendUnlistener = this.renderer.listen(
"document",
"touchend",
(evt) => {
this.closeDrag();
}
);
}
}
// SLIDER MOUSE DRAG
dragSlider(e) {
e = e || window.event;
e.preventDefault();
if (this.wasSlide !== 2) {
this.wasSlide = 0;
}
this.myPos = this.posX - e.clientX;
this.posX = e.clientX;
if (this.theSlider.nativeElement.offsetLeft < this.borderLeft - 1) {
this.closeDrag();
} else if (this.theSlider.nativeElement.offsetLeft > this.borderRight) {
this.theSlider.nativeElement.style.left = this.borderRight + "px";
} else {
this.theSlider.nativeElement.style.left =
this.theSlider.nativeElement.offsetLeft - this.myPos + "px";
}
}
// SLIDER MOUSE UP
closeDrag() {
if (this.theSlider.nativeElement.offsetLeft < this.borderLeft) {
this.theSlider.nativeElement.style.left = this.borderLeft + "px";
} else if (this.theSlider.nativeElement.offsetLeft > this.borderRight - 1) {
this.theSlider.nativeElement.style.left = this.borderRight + "px";
this.expandSliderAnim();
} else if (
this.theSlider.nativeElement.offsetLeft < this.borderRight &&
this.theSlider.nativeElement.offsetLeft > this.borderLeft + 3
) {
// JUMPBACK
// this.theStartValue = this.theSlider.offsetLeft;
this.moveMe();
}
if (this.mousemoveUnlistener) {
this.mousemoveUnlistener();
}
if (this.mouseupUnlistener) {
this.mouseupUnlistener();
}
if (this.touchstartUnlistener) {
this.touchstartUnlistener();
}
if (this.touchendUnlistener) {
this.touchendUnlistener();
}
}
// SLIDER EXPAND ANIMATION
expandSliderAnim() {
// add animation
this.theSlider.nativeElement.style.animationName = "sliderExpands";
this.theSlider.nativeElement.style.animationDuration = "300ms";
this.theSlider.nativeElement.style.animationFillMode = "forwards";
// add count down timer
this.timerText.nativeElement.style.display = "block";
// this.theSlider.nativeElement.innerHTML =
// "<span id='timer'>" + /*timer here:*/ '23:59:59' /*///*/ + "</span><div id='lock' #lock></div>";
this.banText.nativeElement.style.display = "none";
this.theSlider.nativeElement.style.background =
"radial-gradient(50% 50% at 50% 50%, #338EFC 0%, #0450AD 100%)";
// lock icon animation
// let theLock = document.getElementById('lock');
this.theLock.nativeElement.style.animationName = "lockFadeIn";
this.theLock.nativeElement.style.animationDuration = "2s";
// theLock.style.animationFillMode = "forwards";
this.theLock.nativeElement.style.animationDirection = "alternate";
this.theLock.nativeElement.style.animationIterationCount = "infinite";
// document.getElementById('gameName').style.opacity = String(0.3);
// document.getElementById('depositButton').style.opacity = String(0.3);
// document.getElementById('sessionTimer').style.opacity = String(0.3);
setTimeout(function () {
this.wasSlide = 2;
}, 1000);
}
explainBanButton() {
if (this.wasSlide === 2) {
alert("You are blocked from playing for 23:59:59 hours");
this.wasSlide = 2;
} else if (this.wasSlide === 1) {
this.wasSlide = 0;
}
}
// OPEN MODAL WINDOW (TODO) TO EXPLAIN SESSION TIMER FUNCTIONALITY TO THE USER
explainSessionTimer() {
alert(
"this indicates how much time has past since you start you seesion today"
);
}
moveMe() {
// using fix values here, because the sliders
// moves between fix constrains
this.wasSlide = 0;
this.easing = this.easeInCubic(this.step, 0, 12, this.duration);
this.theSlider.nativeElement.style.left = this.easing + "px";
this.step++;
if (this.step > this.duration) {
cancelAnimationFrame(this.repeater);
this.step = 0;
} else {
// bind the context to the func.
this.repeater = requestAnimationFrame(this.moveMe.bind(this));
}
}
easeInCubic(currentIteration, startValue, changeInValue, totalIterations) {
return changeInValue / Math.pow(currentIteration, 0.5) + startValue;
}
}
Template:
<div id="ban_button" (touchstart)="explainBanButton($event)" (mouseup)="explainBanButton($event)">
<div id="slider" #theSlider (touchend)="sliderDown($event)" (touchstart)="closeDrag($event)" (mousedown)="sliderDown($event)" (mouseup)="closeDrag($event)">
<span id="ban_text" #banText>Ban</span>
<div #timerText style="display: none;">
<span id='timer'>23:59:59</span><div id='lock' #lock></div>
</div>
</div>
<span class="ban_button--time__text">24h</span>
<div id="h24"></div>
</div>
Upvotes: 0
Views: 131
Reputation: 9124
Several things:
1st
touchstart and touchend should be switched, shouldn't they?
2nd
You register dragSlider
with touchstart
. I believe that should be touchmove
.
3rd
At least with the desktop browsers mobile emulation I run into the not existing else case, when I change 1st and 2nd.
Upvotes: 1