M1X
M1X

Reputation: 5374

Angular custom toggle not working on mobile

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

Answers (1)

MoxxiManagarm
MoxxiManagarm

Reputation: 9124

Several things:

1st

touchstart and touchend should be switched, shouldn't they?

enter image description here

2nd

You register dragSlider with touchstart. I believe that should be touchmove.

enter image description here

3rd

At least with the desktop browsers mobile emulation I run into the not existing else case, when I change 1st and 2nd.

enter image description here

Upvotes: 1

Related Questions