Using X Store With X Data and X on to Manipulate Arrays in Alpinejs
AlpineJS is almost magical in extending the power that Livewire brings to the front-end of any Laravel app.
In some scenarios it is able to pull off what is only expected of the popular JS frameworks. But sometimes these frameworks could be an overkill, especially when you are building a rather back-end intensive application.
One scenario could be state-management or in simple work persisting some data in the DOM. In comes the Alpine.store()
API.
A simple illustration could be adding value to a multistep form. If you want to read about how to build a multistep form with the help of AlpineJS, you can read this post. We would want to
We define an array variable and a regular variable
ansarray: [0],
nextans: '',
We define a method that would push
an element into the array. The element is passed to the method as parameter by a div
in the DOM.
add(item) {
if (this.ansarray.some((x) => x == clickedans) == false) this.ansarray.push(clickedans);
this.nextans="";
},
We then define a method that would search for an element in the array and return a boolean
result. The search param is again passed to the method.
check(item) {
result = this.ansarray.some((x) => x == checkans);
return result;
},
Note: All the variables and methods in the Store are separated by a comma.
Below is the complete snippet:
<script>
document.addEventListener('alpine:init', () => {
Alpine.store('answers', {
ansarray: [0],
nextans: '',
add(item) {
if (this.ansarray.some((x) => x == item) == false) this.ansarray.push(item);
this.nextans="";
},
check(item) {
result = this.ansarray.some((x) => x == item);
return result;
}
})
})
</script>
Heading over to the page elements:
Your elements might be rendering with some values. We pick up the id
of each item and pass it as the parameter in the add
method call that fires on the x-on:click
event. The add
method would be pushing the id
into the array.
@foreach ($records as $ans)
<div
@click="$store.answers.add({{ $ans->id }})"
>
{{ $ans->description }}
</div>
@endforeach
Note: Is works really well if you have are dealing with inputs
. As you would see in the snippet below, the Livewire component would be saving the value of the selected option in the topics
property. This remains different from the $ans->id
that is being saved in the Alpine’s Store’s array which is saving the list of individual select control IDs.
@foreach ($records->options as $opt)
<div>
<input
type="radio"
value={{ $opt }}
wire:model="topics.{{ $ans->id }}"
@click="$store.answers.add({{ $ans->id }})"
<label for={{ $opt }}>{{ $opt }}</label>
</div>
@endforeach
The same id
is attached to another element that could be a SVG icon which would say have a different color if the id is present in the array. The x-bind:fill
property of the SVG is bound such that if the check
method returns true, the color would change to Red.
<svg
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
class="w-6 h-6"
:fill="$store.answers.check({{ $ans->id }}) ? '#ef4444' : '#ababab'"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M5.25 5.653c0-.856.917-1.398 1.667-.986l11.54 6.348a1.125 1.125 0 010 1.971l-11.54 6.347a1.125 1.125 0 01-1.667-.985V5.653z" />
</svg>