Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Async Select Laravel Package

drpshtiwan/livewire-async-select

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:
    composer require drpshtiwan/livewire-async-select
    php artisan vendor:publish --tag=async-select-assets
    
  2. Layout Integration (critical):
    <head>
        @asyncSelectStyles
        @livewireStyles
    </head>
    <body>
        {{ $slot }}
        @livewireScripts
        @stack('scripts') <!-- Required -->
    </body>
    

First Use Case: Basic Async Select

<livewire:async-select
    wire:model="userId"
    endpoint="/api/users/search"
    placeholder="Search users..."
/>

Backend Route:

Route::get('/api/users/search', function (Request $request) {
    return User::where('name', 'like', "%{$request->search}%")
        ->limit(20)
        ->get(['id', 'name']);
})->middleware('auth:sanctum');

Implementation Patterns

1. Data Binding Workflows

  • Two-way Binding: Use wire:model for automatic sync with Livewire properties.
    <livewire:async-select wire:model="selectedUser" endpoint="/api/users" />
    
  • Default Values: Initialize component property in Livewire class:
    public $selectedUser = 1; // Auto-populates select
    

2. Local vs. Remote Data

  • Local Data: Pass options directly (no API calls):
    <livewire:async-select :options="$users" wire:model="userId" />
    
  • Remote Data: Use endpoint for async loading:
    <livewire:async-select endpoint="/api/categories" wire:model="categoryId" />
    

3. Multi-Select Patterns

  • Enable with multiple attribute:
    <livewire:async-select
        wire:model="selectedTags"
        endpoint="/api/tags"
        multiple
        placeholder="Select tags..."
    />
    
  • Tag Display: Customize with selected-slot:
    <livewire:async-select ...>
        <livewire:slot name="selectedSlot">
            <span class="bg-blue-100 text-blue-800 px-2 py-1 rounded">{{ $option['name'] }}</span>
        </livewire:slot>
    </livewire:async-select>
    

4. Search Optimization

  • Debounce: Default 300ms delay (adjust via debounce attribute).
  • Placeholder Labels: Use value-labels to show selected items without API calls:
    <livewire:async-select
        wire:model="categoryId"
        endpoint="/api/categories"
        :value-labels="[3 => 'Web Dev', 5 => 'Design']"
    />
    

5. Authentication Integration

  • Sanctum/Session Auth: Use async-auth middleware:
    Route::get('/api/secure-data', function () { ... })
        ->middleware('async-auth:sanctum');
    
  • Internal Auth: Pass X-Internal-User header for server-side auth.

6. Custom Slots for UI Control

  • Option Slot: Customize dropdown items:
    <livewire:async-select :options="$products">
        <livewire:slot name="slot">
            <div class="flex items-center">
                <img src="{{ $option['thumbnail'] }}" width="30" class="mr-2">
                <span>{{ $option['name'] }} (${{ $option['price'] }})</span>
            </div>
        </livewire:slot>
    </livewire:async-select>
    
  • Selected Slot: Style selected items:
    <livewire:slot name="selectedSlot">
        <span class="badge badge-primary">{{ $option['name'] }}</span>
    </livewire:slot>
    

7. Suffix Button for Actions

  • Trigger modals or custom logic:
    <livewire:async-select
        suffix-button
        suffix-button-action="openModal"
        placeholder="Select or add new..."
    />
    
    // Alpine.js script
    <script>
        function openModal() {
            @this.call('openAddItemModal');
        }
    </script>
    

Gotchas and Tips

Common Pitfalls

  1. Missing @stack('scripts'):

    • Error: Component fails silently.
    • Fix: Ensure @stack('scripts') is in your layout’s <body>.
    • Debug: Check browser console for Alpine.js errors.
  2. API Response Format:

    • Error: "Invalid data format" if response isn’t ['data' => [...]].
    • Fix: Return data as:
      return response()->json(['data' => $items]);
      
  3. Livewire 4 Slot Issues:

    • Error: Blank rows in dropdown (fixed in v3.0.0+).
    • Fix: Update to latest version or manually clear Livewire cache:
      php artisan livewire:discover
      
  4. Caching Headers:

    • Issue: Stale data due to aggressive caching.
    • Fix: Add Cache-Control: no-cache to API responses:
      return response()->json(['data' => $items])
          ->header('Cache-Control', 'no-cache');
      
  5. Multiple Selection Limits:

    • Issue: max-selections not enforced.
    • Fix: Set explicitly:
      <livewire:async-select ... max-selections="5" />
      

Debugging Tips

  • Network Tab: Verify API calls include X-Internal-User header for auth.
  • Livewire Logs: Check storage/logs/livewire.log for property sync errors.
  • Alpine.js Console: Inspect Alpine directives with:
    console.log(Alpine.store('asyncSelectStore'));
    

Configuration Quirks

  1. Tailwind vs. Bootstrap:

    • Tailwind: Default (classes prefixed with las-).
    • Bootstrap 4: Publish assets and use @asyncSelectBootstrapV4Styles.
    • Custom CSS: Override via las-* classes (e.g., .las-dropdown { z-index: 1000; }).
  2. Debounce Adjustments:

    • Default: 300ms (adjust with debounce="500" for slower networks).
  3. Empty State Handling:

    • No Results: Customize with empty-message:
      <livewire:async-select ... empty-message="No users found" />
      

Extension Points

  1. Custom Headers:

    • Pass via wire:model or Livewire property:
      <livewire:async-select
          wire:model="userId"
          endpoint="/api/users"
          :headers="['X-Custom-Header' => 'value']"
      />
      
  2. Dynamic Endpoints:

    • Use Livewire properties:
      <livewire:async-select
          :endpoint="'/api/' . $resource . '/search'"
          wire:model="selectedId"
      />
      
  3. Server-Side Filtering:

    • Extend API to accept wire:model filters:
      // Livewire component
      public $searchTerm = '';
      public $selectedIds = [];
      
      // API route
      $query->where('name', 'like', "%{$request->searchTerm}%")
            ->whereNotIn('id', $request->selectedIds);
      
  4. Accessibility:

    • Ensure aria-label and aria-controls are set for screen readers:
      <livewire:async-select
          aria-label="Search and select a user"
          wire:model="userId"
          endpoint="/api/users"
      />
      

Performance Optimizations

  • Lazy Loading: Use lazy attribute to defer initial load:
    <livewire:async-select lazy endpoint="/api/large-dataset" />
    
  • Pagination: Implement server-side pagination in API:
    $items = User::where(...)
        ->paginate($request->per_page ?? 20);
    return response()->json(['data' => $items]);
    
  • Caching: Cache API responses (e.g., Laravel’s cache()->remember):
    return cache()->remember("users_{$request->search}", now()->addMinutes(5), function () {
        return User::where(...)->get();
    });
    

Security Notes

  • CSRF Protection: Ensure API routes use api or web middleware with CSRF token.
  • Rate Limiting: Protect async endpoints:
    Route::middleware(['throttle:60,1'])->get('/api/search', ...);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor