javascriptalpine.js

Update table row with async fetch using alpinejs


Each table row has a cell with some "expensive" data loaded on demand; before it is loaded, it shows "?". When that row's button is clicked, the cell is populated.

<table>
  <tbody>

    <!-- rows 1..10  -->

    <tr x-data="{ foo: '?' }">
      <td><span x-text="foo"></span></td>
      <!-- ... -->
      <td><button onclick="foo = await fetchFoo('row-11')">Load</button></td>
    </tr>

    <!-- rows 12... -->

  </tbody>
</table>

<script>
  async function fetchFoo(rowId) {
    let url      = `https://www.example.com/foo/${rowId}`;
    let response = await fetch(url);
    let result   = await response.text();
    return result;
  }
</script>

How do I pass the fetched data from the button to the cell?

UPDATE

Here's a demo showing it doesn't work; I tried various syntaxes:

<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js" defer></script>

<table>
  <tbody>
    <tr x-data="{ foo: '?' }">
      <td>Hello</td>
      <td><span x-text="foo"></span></td>
      <td><button onclick="foo = await fetchFoo('row-1')">Load</button></td>
    </tr>
    <tr x-data="{ foo: '?' }">
      <td>World</td>
      <td><span x-text="foo"></span></td>
      <td><button onclick="async () => { foo = await fetchFoo('row-2') }">Load</button></td>
    </tr>
    <tr x-data="{ foo: '?' }">
      <td>Hi</td>
      <td><span x-text="foo"></span></td>
      <td><button onclick="fetchFoo('row-3')">Load</button></td>
    </tr>
    <!-- rows 4+... -->
  </tbody>
</table>

<script>
  async function fetchFoo(rowIndex) {
    return new Promise(resolve => setTimeout(() => resolve(rowIndex), 1000));
  }
</script>


Solution

  • You must change the onclick to x-on:click:

    <script src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.8/dist/cdn.min.js" defer></script>
    
    <table>
      <tbody>
        <tr x-data="{ foo1: '?' }">
          <td>Hello</td>
          <td><span x-text="foo1"></span></td>
          <td><button x-on:click="foo1 = await fetchFoo('row-1')">Load</button></td>
        </tr>
        <!-- rows 4+... -->
      </tbody>
    </table>
    
    <script>
      async function fetchFoo(rowIndex) {
        return new Promise(resolve => setTimeout(() => resolve(rowIndex), 1000));
      }
    </script>

    UPDATE:

    by using "onclick" you're using basic js directives, you must use x-on:click to use alpine's directives.