Home > front end >  Alpine JS: x-show not reacting to variable change in async function
Alpine JS: x-show not reacting to variable change in async function

Time:02-15

I am trying to build a Login-Modal with Alpine JS. The modal is shown initally when opening the page. I define it like:

<div x-data="login()" x-show="showLoginModal" x-cloak x-transition>
<form action="/token" method="POST"  @submit.prevent="submitData">
        <!-- defining the login form -->
</form>
</div>

The corresponding Javascript part looks like this (leaving out some variables concerned with the data of the form.):

<script>
    let token = undefined
    let showLoginModal = false

    function login() {
         async submitData() { 
             await fetch(await fetch('/token', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded',
                    },
                    body: formBody
                })
                    .then((response) => {
                        if (response.status === 200) {
                            return response.json();
                        } else {
                            throw new Error("Login failed.");
                        }
                    }).then((data) => {
                        token = data.access_token
                        showLoginModal = false
                    })
         }
   }
</script>

What I am trying to achieve here is that the modal is closed at this point. However although the variable is correctly set to false, the modal stays visible.

I am aware that this has something to do with teh variable being set in an asynchronus function. I do not know how to make it work however and have not found a tutorial that does something similar so far.

All help appreciated.

CodePudding user response:

The problem is that login() function is not a valid Alpine.js component. It does not return any data, so showLoginModal is not reactive, therefore Alpine.js cannot detect when you mutate the value of the variable. A loginComponent using Alpine.data() should look like this:

<div x-data="loginComponent()" x-show="showLoginModal" x-cloak x-transition>
  <form action="/token" method="POST"  @submit.prevent="submitData">
    <!-- defining the login form -->
  </form>
</div>

<script>
document.addEventListener('alpine:init', () => {
  Alpine.data('loginComponent', () => ({
    showLoginModal: true,
    token: undefined,

    async submitData() {
      await fetch(...).then((data) => {
          this.token = data.access_token
          this.showLoginModal = false
      })
      
    }
  }))
})
</script>

Note that we have to use the this. prefix in the component definition to access Alpine.js data (that are reactive).

  • Related