Hello
I wanted to try using decorators in a Stimulus controller and I am running into an issue.
I have to add and remove a “spinner” class before and after a fetch function.
Since I have this code at several places I wanted to try using a decorator to make it a little dryer (disclaimer I am just getting started with decorators).
here is my code
import { Controller } from "stimulus";
function toggleBusy(target, name, descriptor) {
const value = descriptor.value;
descriptor.value = function() {
console.log("target :", target);
target.toggleBusyClass = true;
value.call(target);
};
return descriptor;
}
export default class extends Controller {
async fetch() {
this.toggleBusyClass = true;
await this.fakefetch();
this.toggleBusyClass = false;
}
@toggleBusy
async fetchWithDecorator() {
await this.fakefetch();
}
set toggleBusyClass(bool) {
this.element.classList.toggle("spinner", bool);
}
fakefetch() {
console.log("fetch start");
return new Promise(resolve => {
return setTimeout(() => {
console.log("fetch done");
resolve();
}, 1000);
});
}
}
and the simple html
<div data-controller="decorator">
<button data-action="click->decorator#fetch">fetch data </button>
<button data-action="click->decorator#fetchWithDecorator">fetch data with decorator</button>
</div>
The simple fetch
method works perfectly.
The decorated fecthWithDecorator
method doesn’t work. I am getting this error:
TypeError: Cannot read property 'scope' of undefined
at Controller.get [as scope] (controller.js:18)
at Controller.get [as element] (controller.js:25)
at Controller.set toggleBusyClass [as toggleBusyClass] (decorator_controller.js:28)
at Controller.descriptor.value (decorator_controller.js:8)
at Binding.invokeWithEvent (binding.js:52)
at Binding.handleEvent (binding.js:29)
at EventListener.handleEvent (event_listener.js:28)
It seems that I am losing the controller’s context.
For now, I have a working solution without a decorator but just curious if someone has an idea on how to make it work.
PS : Babel is up well configured for decorator
Thanks