It is not necessary to rely on the toast object for management as the for loop can rely directly on the store.
Note that the magic property $store is already defined in Alpine, so variables with the same name should not be declared.
Since the store allows you to add methods to interact with the data, a possible solution is to move the logic there:
<div>
<div class="m-2">
<button id ="triggerBtn"
class="bg-blue-500 hover:bg-blue-700 text-white py-2 px-4 rounded"
>
New alert
</button>
</div>
<div x-data>
<template x-for="(alert, index) in $store.toast.alerts" :key="alert.key">
<div class="mb-3 z-40 drop-shadow-xl flex items-center justify-around w-full max-w-xs p-4 rounded-lg"
:class="{'bg-green-100 text-green-800': alert.type == 'info',
'bg-yellow-100 text-yellow-800': alert.type == 'warn',
'bg-red-100 text-red-800': alert.type == 'error'
}"
role="alert"
>
<div class="inline-flex rounded-lg">
<i x-bind:class="alert.icon" class="fas"></i>
</div>
<div class="ms-3 text-sm font-normal"
x-text="alert.message"
>
</div>
<button type="button"
class="p-1 rounded-lg"
:class="{'text-green-900 hover:text-green-600': alert.type == 'info',
'text-yellow-900 hover:text-yellow-600': alert.type == 'warn',
'text-red-900 hover:text-red-600': alert.type == 'error'
}"
aria-label="Close"
@click="$store.toast.remove(index)"
>
<span class="sr-only">
Close
</span>
<i class="fas fa-times"></i>
</button>
</div>
</template>
</div>
</div>
<script>
// this is for testing
window.alertTypes = [
{message: "Info message", type: "info"},
{message: "Warning message", type: "warn"},
{message: "Error message", type: "error"},
];
document.getElementById("triggerBtn").addEventListener("click", function () {
const {message, type} = window.alertTypes[Math.floor(Math.random() * 3)]; // the message is set randomly for testing
Alpine.store("toast").add(message, type);
});
document.addEventListener("alpine:init", () => {
Alpine.store ("toast", {
alerts: [],
add: function (message = "", type = "info") {
this.alerts.push ({type: type, message: message, key: Date.now()})
},
remove: function (index) {
this.alerts.splice(index, 1);
}
});
});
</script>
Instead of hiding the messages, in my solution I decided to remove the related row from the array, so I removed the visible property but I added a key property (valued with a unique value derived from the date) to allow the x-for loop to understand what was added or removed
I’ve also added a simple management for the colors depending on the alert type
For testing purpose I inserted a global list of values and a button that uses javascript to take a random value from this and add it to the alerts shown
In short, triggering the display of a message is implemented by adding a line, via javascript, to the list stored in the Alpine store
Here the documentation for the Alpine storeIt is not necessary to rely on the toast object for management as the for loop can rely directly on the store.
Note that the magic property $store is already defined in Alpine, so variables with the same name should not be declared.
Since the store allows you to add methods to interact with the data, a possible solution is to move the logic there:
<div class="m-2">
<button id ="triggerBtn"
class="bg-blue-500 hover:bg-blue-700 text-white py-2 px-4 rounded"
>
New alert
</button>
</div>
<div x-data>
<template x-for="(alert, index) in $store.toast.alerts" :key="alert.key">
<div class="mb-3 z-40 drop-shadow-xl flex items-center justify-around w-full max-w-xs p-4 rounded-lg"
:class="{'bg-green-100 text-green-800': alert.type == 'info',
'bg-yellow-100 text-yellow-800': alert.type == 'warn',
'bg-red-100 text-red-800': alert.type == 'error'
}"
role="alert"
>
<div class="inline-flex rounded-lg">
<i x-bind:class="alert.icon" class="fas"></i>
</div>
<div class="ms-3 text-sm font-normal"
x-text="alert.message"
>
</div>
<button type="button"
class="p-1 rounded-lg"
:class="{'text-green-900 hover:text-green-600': alert.type == 'info',
'text-yellow-900 hover:text-yellow-600': alert.type == 'warn',
'text-red-900 hover:text-red-600': alert.type == 'error'
}"
aria-label="Close"
@click="$store.toast.remove(index)"
>
<span class="sr-only">
Close
</span>
<i class="fas fa-times"></i>
</button>
</div>
</template>
</div>
Instead of hiding the messages, in my solution I decided to remove the related row from the array, so I removed the visible property but I added a key property (valued with a unique value derived from the date) to allow the x-for loop to understand what was added or removed
I’ve also added a simple management for the colors depending on the alert type
For testing purpose I inserted a global list of values and a button that uses javascript to take a random value from this and add it to the alerts shown
In short, triggering the display of a message is implemented by adding a line, via javascript, to the list stored in the Alpine store
Here the documentation for the Alpine store