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>