This articles was originally published on Rails Designer
Stimulus' values API has a great change callback function. This allows you to respond whenever a value changes. 🦉
For a quick refresher: the values API allows you read (and write!) data attributes to the controller's element.
You define them like so in the HTML: <div data-controller="counter" data-counter-time-value="10">10</div>
.
Then in the controller define them in the static values
:
export default class extends Controller {
static values = { time: Number }
}
With above controller you might expect a connect function to start the timer.
// app/javascripts/controllers/counter_controller.js
export default class extends Controller {
static values = { time: Number }
connect() {
this.timer = setInterval(() => {
this.timeValue--;
if (this.timeValue > 0) {
this.element.textContent = this.timeValue;
} else {
this.element.textContent = "Time's up!"
clearInterval(this.timer);
}
}, 1000);
}
}
And above might look just fine to you. But I like to keep my functions smaller in scope, and I am pretty sure the next requirement is to add a stop and pause feature (and I need a bridge to show how the changes callbacks can be used).
So let's do a little refactor using Change Callbacks.
export default class extends Controller {
static values = { time: Number }
connect() {
this.timer = null;
this.#start();
}
// private
timeValueChanged() {
if (this.timeValue > 0) {
this.element.textContent = this.timeValue;
} else {
this.element.textContent = "Time's up!";
clearInterval(this.timer);
}
}
#start() {
this.timer = setInterval(() => {
this.timeValue--;
}, 1000);
}
}
timevalueChanged()
is called whenever the this.timeValue
is changed (which is done in #start()
.
Is this better? “The class has gotten bigger!” But I'd argue it is better. Yes, significantly more lines of code, but to me it's easier to follow. The #start
function is only concerned with starting the timer. You can imagine there being a public function, alongside a stop()
and pause()
function.
- show a maximum allowed character count;
- fetch API endpoint when urlValue changes;
- show the selected option from a select-element;
- disable a button on "loading" value.
It is one of those, somewhat, hidden helper functions in Stimulus that if you know it, you see ways to use it in many situations.
Top comments (1)
Have you used change callbacks already? If so, what was the use case?