Evolving stimulus-store
Closed this issue · 1 comments
omarluq commented
Add an api to bind a store value as data attribute to an html element (within the scope of a controller element)
e.g.
import { Controller } from '@hotwired/stimulus';
import { useStore } from 'stimulus-store';
import { counterStore } from './stores/counter';
export default class extends Controller {
static stores = [counterStore]
connect() {
useStore(this);
}
}
<div controller='my-controller'>
<div my-controller-counterStore-value=<%= @likes.count %>></div>
</div>
- changes to the store value attribute on the bond element will automatically qualify as a
setStoreValue
- if a new element with store attribute enters the dom it will automatically qualify as a
setStoreValue
e.g implementation
export function useStore(controller: StoreController) {
const stores: Store[] | undefined = controller.constructor?.stores;
// Keep track of MutationObservers to cleanup later
const mutationObservers: MutationObserver[] = [];
stores?.forEach((store) => {
const controllerName: string = controller.identifier.replace(/_/g, '-');
const storeName: string = camelize(store.name.toString().slice(7, -1), false);
const attributeToWatch: string = `data-${controllerName}-${storeName}-value`;
// Setup a MutationObserver for each store-related attribute
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === "attributes" && mutation.attributeName === attributeToWatch) {
// Retrieve the new value from the mutated attribute
const newValue: StoreValue = mutation.target.getAttribute(attributeToWatch)
// Update the store with the new value
store.set(newValue);
}
});
});
// Observe changes in the controller's element and its children
observer.observe(controller.element, {
attributes: true,
subtree: true,
attributeFilter: [attributeToWatch],
});
mutationObservers.push(observer);
}
const originalDisconnect = controller.disconnect.bind(controller);
controller.disconnect = () => {
// Disconnect all mutation observers
mutationObservers.forEach((observer) => observer.disconnect());
// Call the original disconnect method
originalDisconnect();
};
}
github-actions commented
👋 Thanks for raising an issue.
We will review it and get back to you as soon as possible! 🚀