Hi All
Took a deep dive into Stimulus source code and just released this package!
What this allows one to do is simply declare the controller logic and reduce a lot of boilerplate!
In the following shopping cart example:
When a cart item gets added or removed, or an existing item’s quantity or price is updated
- The cart total will show the correct value
- The checkout button will be enabled or disabled based on the total.
class CartItemController extends Controller {
static targets = ["total"];
static values = {
price: Number,
quantity: { type: Number, default: 1 },
};
static afterLoad(identifier, application) {
useStimulusReactive(identifier, application);
}
connect() {
// item total will be updated when price or quantity changes
this.effect(() => {
this.totalTarget.textContent = (
this.priceValue * this.quantityValue
).toString();
});
}
}
class CartController extends Controller {
static targets = ["checkout", "cartTotal"];
static outlets = ["cart-item"];
static afterLoad(identifier, application) {
useStimulusReactive(identifier, application);
}
connect() {
// total will be updated when items get added or removed
// or when an individual item's price or quantity changes!
const total = this.computed(() =>
this.cartItemOutlets.reduce(
(total, item) => total + item.priceValue * item.quantityValue,
0
)
);
// checkout button will be enabled only when balance is due
this.effect(() => (this.checkoutTarget.disabled = total.value <= 0));
// text content is kept in sync with cart total
this.effect(
() => (this.cartTotalTarget.textContent = total.value.toString())
);
}
}
As you can see there is inter-controller communication and state management and everything just works without needing to wire up any custom events!
How this works is by hooking onto the controller value and outlet changes and making the state reactive using @vue/reactivity
Thanks
Ajai