user12614644
user12614644

Reputation:

Clickable progress bar

I'm working with angular and developed a clickable progress bar with the help of javascript (it was the best I could).

Is there a way to place the slider inside the progress bar but without interfering with the progress visualization?

STACKBLITZ

HTML

<div class="progress aqua" data-width="0%">
    <div class="progress-text">0%</div>
    <div class="progress-bar">
        <div class="progress-text">0%</div>
    </div>
</div>

<input class="slider" id="slider" type="range" name="slider" min="0" max="100" value="0">

COMPONENT

myfuction(){

$(document).ready(function( $ ) {


    $('#slider').on('input',function(e) {
        $('.progress-bar').css('width',(e.target  as HTMLInputElement).value + '%');
    });

    // create an observer instance
    var observer = new MutationObserver(function(mutations) {
      mutations.forEach(function(mutation) {
        if (mutation.type == 'attributes' && mutation.attributeName == 'style') {
            var el   = (mutation.target as HTMLInputElement);
            var width  = el.style.width; 
            var $parentEl =$(el).parent('.progress');
            $parentEl.attr('data-width',width);
            $parentEl.find('.progress-text').text(width);
        }
      });
    });

    // configuration of the observer
    var config = {
        attributes: true,
        attributeFilter: ['style'],
        childList: false,
        characterData: false
    };

    $('.progress-bar').each(function(e) {
        // pass in the target node, as well as the observer options
        observer.observe(this, config);
    })
});
}

Image

The goal is to increase progress with clicks, even if I use the slider to do so, but if it is possible to remove the slider and make the progress bar functional even better.

Upvotes: 3

Views: 887

Answers (2)

Eldar
Eldar

Reputation: 10790

I know this is already answered but why you use angular if you will manipulate DOM with juqery and mutation observers. Angular is there to abstract that kind of things from you. You will see how it is easier when you use the power of angular binding :

export class AppComponent {

  percentage: string = "0%"; // just expose a porperty

  private updateSliderToggle: boolean = false;

  startUpdateSlider() {
    this.updateSliderToggle = true;
  }

  endUpdateSlider() {
    this.updateSliderToggle = false;
  }

  updateSlider(event) {
    if (this.updateSliderToggle) {
      let percentage: number = Math.floor(
        (event.layerX / (event.target.offsetWidth - 3)) * 100
      );

      if (percentage > 100) {
        percentage = 100;
      } else if (percentage < 0) {
        percentage = 0;
      }
      this.percentage = percentage + "%"; // and manipulate that property
    }
  }
}

In your template make necessary bindings :

<div class="progress aqua" [attr.data-width]="percentage" (mousedown)="startUpdateSlider()"
    (mouseup)="endUpdateSlider()" (mouseleave)="endUpdateSlider()" (mousemove)="updateSlider($event)">
    <div class="progress-text">{{percentage}}</div>
    <div class="progress-bar" [style.width]="percentage">
        <div class="progress-text">{{percentage}}</div>
    </div>
</div>

Stackblitz

Upvotes: -1

pascalpuetz
pascalpuetz

Reputation: 5428

Just don't use the HTMLInputElement but listen to mouseevents and calculate the percentage yourself.

In your component.ts add the following functions:


private updateSliderToggle:boolean = false;

startUpdateSlider() {
  this.updateSliderToggle = true;
}

endUpdateSlider() {
  this.updateSliderToggle = false;
}

updateSlider(event) {
  if (this.updateSliderToggle) {
    let percentage:number = Math.floor(event.layerX / (event.target.offsetWidth - 3) * 100);

    // Might happen, as we set the max to -3 to reach 100% easier.
    if (percentage > 100) {
      percentage = 100;
    } else if (percentage < 0) {
      percentage = 0;
    }

    console.log(event);
    console.log(event.layerX, event.target.offsetWidth);
    $('.progress-bar').css('width', percentage + '%');
  }
} 

And in your component.html change your markup to

<div class="progress aqua" data-width="0%" (mousedown)="startUpdateSlider()" (mouseup)="endUpdateSlider()" (mouseleave)="endUpdateSlider()" (mousemove)="updateSlider($event)" >
  <div class="progress-text">0%</div>
  <div class="progress-bar">
    <div class="progress-text">0%</div>
  </div>
</div>

Here is a working Stackblitz

Upvotes: 3

Related Questions