In this article, you will learn how to work with arrays in Alpine.js stores.
Alpine.js is a rugged, minimal framework for composing JavaScript behavior in your markup.
The Alpine.store() API offers global state management.
This article is compatible with Alpine.js V3.
You will be building a tiny application that lets you create, view and updates messages.
Start with the following minimal HTML.
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
<form>
<div>
<label>Message:</label>
<textarea name="message" required></textarea>
</div>
<button>Submit</button>
</form>
<div>
<hr />
<div>My first message</div>
<button>lowercase</button>
<button>UPPERCASE</button>
<button>Delete</button>
<hr />
<div>My second message</div>
<button>lowercase</button>
<button>UPPERCASE</button>
<button>Delete</button>
</div>
</body>
</html>
Let's enhance it with some Alpine.js magic. Add the following script
tag inside head
.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="//unpkg.com/alpinejs" defer></script>
</head>
<body>
<!-- ... -->
</body>
</html>
- The
defer
attribute makes the script execute after the page has finished parsing. - The two forward slashes are a common shorthand for "whatever protocol is being used right now".
x-data
marks a chunk of HTML that should be controlled by Alpine.js.
Create an empty store (I have called it main
, but you can pick what you prefer).
<body x-data>
<!-- ... -->
<script>
document.addEventListener("alpine:init", () => {
Alpine.store("main", {});
});
</script>
</body>
Add the required state and helper functions to your store.
Alpine.store("main", {
// The array of all messages
messages: [],
// The next message to add, its value is bound to the textarea field
newMessage: "",
// Adds the current value of `newMessage` to the array of messages
addMessage(message) {
this.messages.push(message);
this.newMessage = "";
},
// Given an index, changes the capitalization of the message to lower case
lowerCaseMessage(index) {
this.messages[index] = this.messages[index].toLowerCase();
},
// Given an index, changes the capitalization of the message to upper case
upperCaseMessage(index) {
this.messages[index] = this.messages[index].toUpperCase();
},
// Given an index, removes the message from the array
deleteMessage(index) {
this.messages = this.messages.filter((_, i) => i !== index);
},
});
Let's implement the form.
When working with a store's properties and functions, you need to prefix all calls with $store.nameOfYourStore
.
To set up input reactivity, use x-model
to bind newMessage
to the textarea.
The form element emits a submit event you can listen to using the @submit
directive.
Add the .prevent
modifier to prevent the browser from submitting a native form request.
<!-- ... -->
<form @submit.prevent="$store.main.addMessage($store.main.newMessage)">
<div>
<label>Message:</label>
<textarea
name="message"
required
x-model="$store.main.newMessage"
></textarea>
</div>
<button>Submit</button>
</form>
<!-- ... -->
Let's implement the list.
Use x-for
to loop over the array.
<!-- ... -->
<div>
<template x-for="message, index in $store.main.messages">
<div>
<hr />
<div x-text="message"></div>
<button @click="$store.main.lowerCaseMessage(index)">lowercase</button>
<button @click="$store.main.upperCaseMessage(index)">UPPERCASE</button>
<button @click="$store.main.deleteMessage(index)">Delete</button>
</div>
</template>
</div>
<!-- ... -->
You can access a store's state and call its functions externally.
<!DOCTYPE html>
<html lang="en">
<body x-data>
<form @submit.prevent="$store.main.addMessage($store.main.newMessage)">
<!-- ... -->
</form>
<div>
<!-- ... -->
</div>
<script>
// ...
</script>
<script>
let i = 0;
setInterval(() => {
Alpine.store("main").addMessage(`Hello, Interval! (${i})`);
i++;
}, 3000);
</script>
</body>
</html>
Thank you for reading through, feel free to leave a comment below.