Laravel+AlpineJS:如何在foreach循环内按需单独隐藏按钮(解决x-if/x-show全显全隐问题)
Hey there! I see the issue you're having—when trying to control button visibility with x-if or x-show, all buttons are showing or hiding at the same time. That's because right now you're using a single global state (loadBtn) that every row shares. Let's fix this by giving each tenant its own individual state to control the buttons in its row.
Step 1: Add Per-Tenant Loading State
First, when you fetch your tenant data, add an isLoading property to each tenant object. This will let us track the state for each row independently:
function serviceTenants(){ return { tenants: [], loadingTable(){ fetch('list') .then(response => response.json()) .then(data => { // Map over the data to add isLoading to each tenant this.tenants = data.data.map(tenant => ({ ...tenant, isLoading: false })); }); }, deleteTenant(tenantId){ // Find the specific tenant we're deleting const targetTenant = this.tenants.find(tenant => tenant.id === tenantId); if (!targetTenant) return; // Set this tenant's loading state to true targetTenant.isLoading = true; // Perform your delete fetch request fetch(`/delete/${tenantId}`, { method: 'DELETE' }) .then(response => { // On success, remove the tenant from the list this.tenants = this.tenants.filter(tenant => tenant.id !== tenantId); }) .catch(error => { console.error('Delete failed:', error); // If delete fails, reset the loading state so buttons reappear targetTenant.isLoading = false; }); } } }
Step 2: Update the Template to Use Per-Tenant State
Now modify your table template to use the tenant.isLoading state instead of the global loadBtn. You can choose between x-show (hides via CSS) or x-if (adds/removes from DOM) depending on your needs:
Using x-show (simpler for visibility toggles):
<div class="iq-card-body" x-data="serviceTenants()" x-init="loadingTable()"> <table class="table table-bordered table-responsive-md table-striped_ text-center" id="laravel_crud"> <thead> <tr> <th>Company</th> <th>Plan</th> <th>created at</th> <td colspan="3"></td> </tr> </thead> <tbody> <template x-for="tenant in tenants"> <tr> <td x-text="tenant.name"></td> <td x-text="tenant.plan"></td> <td x-text="tenant.created"></td> <td width="180"> <button class="btn iq-bg-info btn-rounded btn-sm my-0 float-left" x-show="!tenant.isLoading">Upgrade</button> <button class="btn iq-bg-danger btn-rounded btn-sm my-0 float-left ml-2" @click="deleteTenant(tenant.id)" x-show="!tenant.isLoading"> {{__('Delete')}} </button> <!-- Optional: Show loading state when isLoading is true --> <span class="float-left" x-show="tenant.isLoading">Deleting...</span> </td> </tr> </template> </tbody> </table> </div>
Using x-if (if you need to remove elements from the DOM):
<div class="iq-card-body" x-data="serviceTenants()" x-init="loadingTable()"> <table class="table table-bordered table-responsive-md table-striped_ text-center" id="laravel_crud"> <thead> <tr> <th>Company</th> <th>Plan</th> <th>created at</th> <td colspan="3"></td> </tr> </thead> <tbody> <template x-for="tenant in tenants"> <tr> <td x-text="tenant.name"></td> <td x-text="tenant.plan"></td> <td x-text="tenant.created"></td> <td width="180"> <template x-if="!tenant.isLoading"> <button class="btn iq-bg-info btn-rounded btn-sm my-0 float-left">Upgrade</button> </template> <template x-if="!tenant.isLoading"> <button class="btn iq-bg-danger btn-rounded btn-sm my-0 float-left ml-2" @click="deleteTenant(tenant.id)">{{__('Delete')}}</button> </template> <template x-if="tenant.isLoading"> <span>Deleting...</span> </template> </td> </tr> </template> </tbody> </table> </div>
Why This Works
By adding isLoading directly to each tenant object, we're giving every row its own independent state. When you click the Delete button for a specific tenant, only that tenant's isLoading property gets updated—so only the buttons in that row will hide, while others stay visible.
内容的提问来源于stack exchange,提问作者alex spencer

