I created an AlpineJs Toaster and I want to trigger it from javascript code to call it from anywhere.
I tried to update the store but it's not working. What I am missing ?
$("#triggerBtn").on("click", function(){ //that just an example with jquery
Alpine.store('toast',{type:"danger",message:"hello",visible:true});
})
document.addEventListener("alpine:init",()=>{
Alpine.store("toast",{type:null,message:null,alerts:[]});
Alpine.data('toast', () => ({
type:null,
message:null,
alerts:[],
init(){
var $store = Alpine.store("toast");
this.type = $store.type;
this.message = $store.message;
this.alerts = $store.alerts;
var icon = "fa fa-info-circle text-info-600";
this.alerts.push(
{
icon:icon,
message:this.message,
visible:true
}
Alpine.store('toast').alerts = this.alerts;
},
close(){
this.show=false
}
}))
})
<div x-data="toast">
<template x-for="alert in $store.toast.alerts">
<div x-show="alert.visible" id="liveToastAlpine"
class="mb-3 z-40 drop-shadow-xl flex items-center w-full max-w-xs p-4 text-gray-500 bg-white rounded-lg"
role="alert">
<div
class="inline-flex items-center justify-center flex-shrink-0 w-8 h-8 text-info-500 bg-info-100 rounded-lg dark:bg-info-700 dark:text-info-200">
<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="ms-auto -mx-1.5 -my-1.5 bg-white text-gray-400 hover:text-gray-900 rounded-lg"
data-dismiss-target="#liveToastTemplate" aria-label="Close" @click="alert.visible=false">
<span class="sr-only">Close</span>
<i class="fas fa-times"></i>
</button>
</div>
</template>
</div>
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 store