In this quick tutorial, I'll show how to create a StateActions
Component Part which is a great way to create versatile, common, re-usable actions across all your Modulo JS components. The end result is already useful, and also gives you a useful structure to continue writing more actions. Best of all, the actions you define are generic, meaning they can be applied to future components regardless of what specific state variables they are using.
First, some background: Modulo JS is recently released beginner-friendly HTML web component framework, with a "Jamstack" set of features inspired by Svelte, Vue.js, React.js. It's only 2000 lines and has no dependencies, and runs entirely in the browser (no terminal usage needed). The feature that matters to us is the Custom Component Part feature. This allows us to do something really important in frontend: Write and re-use generic JavaScript actions.
So, let's get down to business!
Step 1 - Creating a CPart
Creating and registering a CPart:
class StateActions {
// TODO ...
}
modulo.register('cpart', StateActions);
To include this CPart in a Modulo project (at the top level, e.g. your /static/index.html
):
<Configuration -src="./js/StateActions.js"></Configuration>
Step 2 - Using in a Component
Adding a method, and then using the CPart and attaching it as a click function:
class StateActions {
setToThree(key, value) {
this.element.cparts.state.data.num = 3;
}
}
modulo.register('cpart', StateActions);
And how to use in your Component definitions:
<Template>
<button @click:=stateactions.setToThree>Num: {{ state.num }}</button>
</Template>
<State
num:=1
></State>
<!-- Here is where we actually include the State Actions: -->
<StateActions></StateActions>
Step 3 - Making generic
The most complicated step is next: Transforming the specific method into a generic action. We'll use the this.attrs
so that the user of our generic CPart can specify which State variables they wish to modify. Now, instead of having to hardcode the value, let's make it more configurable, so it can be a "generic" action that can apply to any value:
class StateActions {
initializedCallback() {
const results = {};
// Loop through all configuration attributes:
for (let [ key, methodName ] of Object.entries(this.attrs)) {
results[key] = this.set.bind(this, key); // Bind "set" method with "key", so it remembers this
}
return results;
}
set(key, value) {
this.element.cparts.state.data[key] = value;
// "Propagate" is added so bound forms, components, etc get rerendered
this.element.cparts.state.propagate(key, value);
}
}
modulo.register('cpart', StateActions);
And to use:
<Template>
<button @click:=stateactions.num payload:=3>Num: {{ state.num }}</button>
</Template>
<State
num:=1
></State>
<StateActions
num
></StateActions>
Step 4 - Adding another generic method
Cleaning up and final results with a default value, and adding "push" generic action:
class StateActions {
initializedCallback() {
const results = {};
for (let [ key, methodName ] of Object.entries(this.attrs)) {
methodName = methodName || 'set'; // Default to set
results[key] = this[methodName].bind(this, key);
}
return results;
}
set(key, value) {
this.element.cparts.state.data[key] = value;
this.element.cparts.state.propagate(key, value);
}
push(key, value) {
const arr = this.element.cparts.state.data[key];
arr.push(value);
this.element.cparts.state.propagate(key, arr);
}
}
modulo.register('cpart', StateActions);
<Template>
<button @click:=stateactions.num payload=3>Num: {{ state.num }}</button>
<button @click:=stateactions.list payload="bread">Add to list: {{ state.list }}</button>
</Template>
<State
num:=1
list:=[]
></State>
<StateActions
num
list=push
></StateActions>
Hopefully this tutorial will help you add re-usable JavaScript actions to your next Modulo JS project. If you found this interesting and are new to Modulo JS, then consider taking the interactive tutorial, or just playing around with some examples to get a better idea of what you can do with this mighty little 2000 line framework. Either way, feel free to follow me here for more tutorials like this. Thanks for reading!
Top comments (0)