I am using two ngx-sliders with an Anuglar form and want the two sliders (a ‘Value’ and a ‘Band’) both with two handles to be connected to each other depending on the mapping. As well as this, I a text input that has the same form control as the value slider. The user can provide a value using either the slider or the value box, and the bands should update correctly for both.
<div class="custom-slider">
<ngx-slider
[options]="sliderOptionsBands"
[value]="sForm.get('minBand')?.value"
[highValue]="sForm.get('maxBand')?.value"
(valueChange)="onBandChange('minBand', $event)"
(highValueChange)="onBandChange('maxBand', $event)"></ngx-slider>
</div>
<label
for="valueInputMin"
class="form-label fw-bold mt-4">
Value
</label>
<div class="custom-slider mb-2">
<ngx-slider
[options]="sliderOptionsValue"
[value]="sForm.get('minValue')?.value"
[highValue]="sForm.get('maxValue')?.value"
(valueChange)="onValueChange('minValue', $event)"
(highValueChange)="onValueChange('maxValue', $event)"></ngx-slider>
</div>
<div class="input-group">
<span
for="valueInputMin"
class="input-group-text">
Min
</span>
<input
type="number"
min="10"
max="1000"
step="0.001"
class="form-control"
formControlName="minValue"
id="valueInputMin" />
<span
for="valueInputMax"
class="input-group-text">
Max
</span>
<input
type="number"
min="10"
max="1000"
step="0.001"
class="form-control"
formControlName="maxValue"
id="valueInputMax" />
</div>
Here are the ngx-slider options:
sliderOptionsValue: Options = {
floor: 10,
ceil: 1000,
step: 1,
ticksArray: [0, 50, 100, 150, 200, 250, 300, 350, 400, 450, 500, 550, 600, 650, 700, 750, 800, 850, 900, 950, 1000],
showTicks: true
};
sliderOptionsBands: Options = {
floor: 1,
ceil: 10,
step: 1,
tickStep: 1,
showTicks: true,
showTicksValues: true
};
bandToValueMap = [
{band: 1, min: 10, max: 70},
{band: 2, min: 71, max: 120},
{band: 3, min: 121, max: 190},
{band: 4, min: 191, max: 250},
{band: 5, min: 251, max: 330},
{band: 6, min: 331, max: 385}
];
I want the two sliders to work interconnected as I said, as well as the text input. Is there a way to do this without getting stuck in recursive loops where the value is set by the user in the text box and then glitches between the entered value and the band min or max. These are the methods I have so far:
onBandChange(controlName: string, value: number): void {
if (this.isUpdating) return; // Prevent recursion
this.isUpdating = true;
this.sForm.get(controlName)?.setValue(value);
const minBand = this.sForm.get('minBand')?.value;
const maxBand = this.sForm.get('maxBand')?.value;
if (minBand && maxBand) {
const minValue = this.bandToValueMap.find((b) => b.band === minBand)?.min ?? 10;
const maxValue = this.bandToFrequencyMap.find((b) => b.band === maxBand)?.max ?? 385;
const currentMinValue = this.sForm.get('minValue')?.value;
const currentMaxValue = this.sForm.get('maxValue')?.value;
// Only update Values if they differ to avoid triggering unnecessary updates
if (minValue !== currentMinValue) {
this.sForm.get('minValue')?.setValue(minValue);
}
if (maxValue !== currentMaxValue) {
this.sForm.get('maxValue')?.setValue(maxValue);
}
}
this.isUpdating = false;
}
onValueChange(controlName: string, value: number): void {
if (this.isUpdating) return; // Prevent recursion
this.isUpdating = true; // Set the flag to prevent future updates
// Update the value control value
this.sForm.get(controlName)?.setValue(value);
// Calculate the bands based on the updated frequency range
const minValue = this.sForm.get('minValue')?.value;
const maxValue = this.spForm.get('maxValue')?.value;
const minBand = this.bandToValueMap.find((b) => b.min <= minValue && b.max >= minValue)?.band ?? 1;
const maxBand = this.bandToValueMap.find((b) => b.min <= maxValue && b.max >= maxValue)?.band ?? 6;
// Only update bands if they actually change to avoid triggering unnecessary updates
const currentMinBand = this.sForm.get('minBand')?.value;
const currentMaxBand = this.sForm.get('maxBand')?.value;
if (minBand !== currentMinBand) {
this.sForm.get('minBand')?.setValue(minBand, { emitEvent: false });
}
if (maxBand !== currentMaxBand) {
this.sForm.get('maxBand')?.setValue(maxBand, { emitEvent: false });
}
// Reset the flag after the update
this.isUpdating = false;
}