Reputation:
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?
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);
})
});
}
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
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>
Upvotes: -1
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