Bitwise
Bitwise

Reputation: 8451

Wait for request to complete before displaying data - Alpine.js

I'm struggling with a timing issue in which I'm getting an error because the data response from the API I'm fetching is not done before trying to process the data.

Here is my example:

### Template

<div class="container mx-auto" x-data="loadIdentities()">
  <template x-for="item in filteredIdentities" :key="item">
    <h6 x-text="item.name"></h6>
    <em x-text="item.role"></em>
  </template>
</div>

### SCRIPT

<script>
  function loadIdentities() {
    return {
      search: "",
      myData: "",
      get filteredIdentities() {
        fetch(`/api_endpoint`)
          .then(res => res.json())
          .then(data => {
            this.myData = data
          }
        )

        var foundIdentities = this.myData.filter((item) => {
          return item.name
            .toLowerCase()
            .includes(this.search.toLowerCase());
        });


        return foundIdentities
      },
    };
  }
</script>

ERROR:

Uncaught TypeError: this.myForData.filter is not a function

Is there a nice way that I can have the processing of the javascript wait for the API request to complete and the data to populate from the API?

Upvotes: 0

Views: 3115

Answers (2)

ptts
ptts

Reputation: 2086

You can also return an empty array as long as there is no data to display.

Example:

(here I load the Identities once using the init() method and then filter using the getFilteredIdentities method)

<link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
<script src="//unpkg.com/alpinejs" defer></script>

<div class="p-5 mx-auto" x-data="loadIdentities()">
  <input class="border px-2" placeholder="Filter Identities..." x-model="search"
    x-on:change="setFilteredItentities()" />
  <p class="text-gray-400" x-show="isLoading">Loading Identities...</p>
  <template x-for="item in getFilteredIdentities" :key="item.id">
    <div class="mt-2 flex items-center">
      <h6 x-text="item.first_name"></h6>
      <p class="text-xs text-gray-500 ml-2" x-text="item.email"></p>
    </div>
  </template>
</div>

<script>
  function loadIdentities() {
    return {
      search: "",
      isLoading: false,
      allIdentities: [],
      init() {
        this.isLoading = true
        fetch(`https://reqres.in/api/users`)
          .then(res => res.json())
          .then(data => {
            this.allIdentities = data.data
          })
        this.isLoading = false;
      },
      getFilteredIdentities() {
        if (!this.allIdentities || !this.search) {
          return this.allIdentities
        }
        var result = this.allIdentities.filter((item) => {
          return item.first_name
            .toLowerCase()
            .includes(this.search.toLowerCase());
        })
        return result
      }
    }
  }
</script>

Upvotes: 1

Riccardo Belingheri
Riccardo Belingheri

Reputation: 11

You can use await. Declare the function as async like: async function filteredIdentities (){

 const response = await fetch('stuff')
 const data = await response.json()
 return data.filter((item) => 
return item.name
        .toLowerCase()
        .includes(this.search.toLowerCase());
    });
}

The function return a promise and when It Will resolved you have an array

Upvotes: 0

Related Questions