Logo

dev-resources.site

for different kinds of informations.

Augmenting the client with Alpine.js

Published at
10/3/2024
Categories
alpinejs
webdev
ajax
ssr
Author
nfrankel
Categories
4 categories in total
alpinejs
open
webdev
open
ajax
open
ssr
open
Author
8 person written this
nfrankel
open
Augmenting the client with Alpine.js

This post is part of a series comparing different ways to implement asynchronous requests on the client, which is colloquially known as AJAX. I dedicated the previous post to Vue.js; I'll dedicate this one to Alpine.js - not to be confused with Alpine Linux.

I'll follow the same structure as previously.

Laying out the work

Here's the setup, server- and client-side.

Server-side

Here is how I integrate Thymeleaf and Alpine.js in the POM:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>        <!--1-->
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>  <!--1-->
    </dependency>
    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>webjars-locator</artifactId>                <!--1-->
        <version>0.52</version>
    </dependency>
    <dependency>
        <groupId>org.webjars.npm</groupId>
        <artifactId>alpinejs</artifactId>                       <!--2-->
        <version>3.14.1</version>
    </dependency>
    <dependency>
        <groupId>org.webjars.npm</groupId>
        <artifactId>axios</artifactId>                          <!--1-->
        <version>1.7.3</version>
    </dependency>
</dependencies>
Enter fullscreen mode Exit fullscreen mode
  1. Same as last week with Vue
  2. Alpine instead of Vue

It's similar to Vue's setup.

Client-side

Here's the code on the HTML side:

<script th:src="@{/webjars/axios/dist/axios.js}" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/axios.min.js"></script> <!--1-->
<script th:src="@{/webjars/alpinejs/dist/cdn.js}" src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js" defer></script> <!--2-->
<script th:src="@{/alpine.js}" src="../static/alpine.js"></script>  <!--3-->
<script th:inline="javascript">
/*<![CDATA[*/
    window.alpineData = {                                           <!--4-->
        title: /*[[${ title }]]*/ 'A Title',
        todos: /*[[${ todos }]]*/ [{ 'id': 1, 'label': 'Take out the trash', 'completed': false }]
    }
/*]]>*/
</script>
Enter fullscreen mode Exit fullscreen mode
  1. Axios helps making HTTP requests
  2. Alpine itself
  3. Our client-side code
  4. Set the data

As for the POM, it's the same code for Alpine as for Vue.

The Alpine code

We want to implement the same features as for Vue.

Our first steps into Alpine

The first step is to bootstrap the framework. We already added the link to our custom alpine.js file above.

document.addEventListener('alpine:init', () => {                    //1
    Alpine.data('app', () => ({                                     //2
        // The next JavaScript code snippets will be inside the block
    }))
})
Enter fullscreen mode Exit fullscreen mode
  1. Run the block when the alpine:init event is triggered; the triggering event is specific to Alpine.
  2. Bootstrap Alpine and configure it to manage the HTML fragment identified by app

We now set the app id on the HTML side.

<div id="app">
</div>
Enter fullscreen mode Exit fullscreen mode

Until now, it's very similar to Vue.js, a straight one-to-one mapping.

Unlike Vue.js, Alpine doesn't seem to have templates. The official UI components are not free. I found an Open Source approach, but it's unavailable on WebJars.

Basic interactions

Let's implement the check of the complete checkbox.

Here's the HTML code:

<input type="checkbox" :checked="todo.completed" @click="check(todo.id)"> <!--1-->
<input type="checkbox" :checked="todo.completed" @click="check" />  <!--2-->
Enter fullscreen mode Exit fullscreen mode
  1. Alpine code
  2. Vue code

The code is very similar, with the difference that Alpine allows passing parameters.

On the Javascript side, we must define the function, and that's all:

Alpine.data('app', () => ({
    check(id) {
        axios.patch(`/api/todo/${id}`, {checked: event.target.checked})
    }
}))
Enter fullscreen mode Exit fullscreen mode

Client-side model

You might wonder where the todo above comes from. The answer is: from the local model.

We initialize it in the app or to be more precise, we initialize the list:

Alpine.data('app', () => ({
    title: window.alpineData.title,                                 //1
    todos: window.alpineData.todos,                                 //2
}))
Enter fullscreen mode Exit fullscreen mode
  1. Initialize the title even if it's read-only
  2. Initialize the todos list; at this point, it's read-only but we are going to update it the next section

Updating the model

In this section, we will implement adding a new Todo.

Here's the HTML snippet:

<form>
    <div class="form-group row">
        <label for="new-todo-label" class="col-auto col-form-label">New task</label>
        <div class="col-10">
            <input type="text" id="new-todo-label" placeholder="Label" class="form-control" x-model="label" /> <!--1-->
        </div>
        <div class="col-auto">
            <button type="button" class="btn btn-success" @click="create()">Add</button> <!--2-->
        </div>
    </div>
</form>
Enter fullscreen mode Exit fullscreen mode
  1. The x-model defines a model and binds the label property defined in app
  2. Define the behavior of the button, as in the previous section

The related code is the following:

Alpine.data('app', () => ({
    label: '',                                                      //1
    create() {
        axios.post('/api/todo', {label: this.label}).then(response => { //2
            this.todos.push(response.data)                          //3
        }).then(() => {
            this.label = ''                                         //4
        })
    }
}))
Enter fullscreen mode Exit fullscreen mode
  1. Define a new label property
  2. Send a POST request with the label value as the JSON payload
  3. Get the response payload and add it to the local model of Todo
  4. Reset the label value

Conclusion

Alpine is very similar to Vue, with the notable difference of the lack of templating; components are only available via a price. All other features have an equivalent.

I may need to be corrected because the documentation is less extensive. Also, Vue is much more popular than Alpine.

The complete source code for this post can be found on GitHub:

GitHub logo ajavageek / compare-frontends

Demo code for the series on AJAX and SSR

To go further:


Originally published at A Java Geek on September 29th, 2024

ssr Article's
30 articles in total
Favicon
Custom builder for Angular: My way
Favicon
Setting Up Dual Compilation (SSR + CSR) in ViteJS with vite-plugin-builder
Favicon
# Key New Features in React Router 7: Embracing the Remix Future
Favicon
Beginner SEO in React JS - React Helmet
Favicon
Setting up partial SSR for a React + TypeScript + webpack app from scratch
Favicon
Create an SSR Application with Vite, React, React Query and React Router
Favicon
Understanding Web Rendering: Performance Implications and Use Cases
Favicon
Make EditorJS work in Svelte(kit) SSR
Favicon
Client-side Rendering & Server-side Rendering
Favicon
A Practical Guide to CSR and SSR with React 19 and esbuild
Favicon
Fixing SSR Rendering Issues with Angular Resolver for Async Pipe Data
Favicon
Choosing Remix as a Server-Side Rendering (SSR) Framework
Favicon
Implementing Server-Side Rendering (SSR) with Next.js and Firebase for SEO-Friendly React Apps 🚀
Favicon
Do You Need to SSR Your Web Components?
Favicon
Web Components and SSR - 2024 Edition
Favicon
Dark side of Next.js - App Router
Favicon
How to achieve unified management of four types of global state data in Vue3?
Favicon
What do SSR, CSR, ISR and SSG mean? A complete guide for web developers
Favicon
Vue 3.5 “Tengen Toppa Gurren Lagann” Innovations: Advanced Features and Most Powerful Updates 🚀
Favicon
Inertiajs Server-side Rendering (SSR) For React (Vite Setup)
Favicon
Vaadin, the battery-included server-side AJAX framework
Favicon
How to add Supabase Auth to Astro
Favicon
Dive into Next.js Server-Side Rendering (SSR): From SPA to ISR
Favicon
Why do client components render as SSR in nextjs, marking components as "use client" still render its html as SSR why?
Favicon
Augmenting the client with Alpine.js
Favicon
Augmenting the client with Vue.js
Favicon
Server-Side Rendering (SSR): Uma Solução para SEO e Performance em Aplicações React
Favicon
SSR and CSR Explained
Favicon
A short history of AJAX and SSR
Favicon
How to Do Server-Side Rendering (SSR) in Next.js

Featured ones: