Weave 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

Select Autocompleter Bundle Laravel Package

danilovl/select-autocompleter-bundle

Symfony bundle that turns standard form fields into Select2 autocompleters, loading choices on demand via remote AJAX instead of rendering huge option lists. Ships with sensible defaults for properties, limits, widgets, and CDN assets.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require danilovl/select-autocompleter-bundle
    

    Register the bundle in config/bundles.php:

    Danilovl\SelectAutocompleterBundle\SelectAutocompleterBundle::class => ['all' => true],
    
  2. Basic Configuration: Add to config/packages/danilovl_select_autocompleter.yaml:

    danilovl_select_autocompleter:
        select2:
            theme: "bootstrap4" # or 'bootstrap5', 'classic', 'bootstrap4-dark'
            width: "100%"
            placeholder: "Search..."
    
  3. First Use Case: Create a form type extending AbstractAutocompleterType:

    use Danilovl\SelectAutocompleterBundle\Form\Type\AbstractAutocompleterType;
    
    class UserAutocompleteType extends AbstractAutocompleterType
    {
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults([
                'class' => User::class,
                'choice_label' => 'fullName',
                'ajax_route' => 'user_autocomplete',
                'min_input_length' => 2,
            ]);
        }
    }
    
  4. Route for Autocomplete: Define a route in config/routes.yaml:

    user_autocomplete:
        path: /api/users/autocomplete
        controller: App\Controller\UserAutocompleteController::class
        methods: GET
    

    Controller:

    use Danilovl\SelectAutocompleterBundle\Controller\AutocompleteControllerTrait;
    
    class UserAutocompleteController extends AbstractController
    {
        use AutocompleteControllerTrait;
    
        public function __invoke(Request $request, UserRepository $userRepository)
        {
            return $this->handleAutocomplete($request, $userRepository, 'fullName');
        }
    }
    
  5. Use in Form:

    $builder->add('user', UserAutocompleteType::class);
    

Implementation Patterns

Common Workflows

1. Basic Integration with Existing Forms

Replace standard EntityType with AbstractAutocompleterType:

// Before
$builder->add('user', EntityType::class, ['class' => User::class]);

// After
$builder->add('user', UserAutocompleteType::class);

2. Customizing Autocomplete Behavior

Override default options in configureOptions:

$resolver->setDefaults([
    'ajax_route' => 'custom_route',
    'min_input_length' => 1,
    'multiple' => true,
    'allow_clear' => true,
    'select2_options' => [
        'ajax' => [
            'dataType' => 'json',
            'delay' => 250,
        ],
    ],
]);

3. Dynamic Route Parameters

Pass dynamic parameters via ajax_route_parameters:

$resolver->setDefaults([
    'ajax_route' => 'department_autocomplete',
    'ajax_route_parameters' => ['company_id' => $companyId],
]);

4. Handling Complex Data Structures

Customize the response format in the controller:

public function __invoke(Request $request, ProductRepository $productRepository)
{
    $results = $productRepository->findByName($request->query->get('term'));

    return $this->json(array_map(function ($product) {
        return [
            'id' => $product->getId(),
            'text' => $product->getName(),
            'price' => $product->getPrice(),
        ];
    }, $results));
}

Update the form type to handle custom fields:

$resolver->setDefaults([
    'template' => '@DanilovlSelectAutocompleter/autocompleter_widget.html.twig',
    'select2_options' => [
        'templateResult' => 'customTemplate',
        'templateSelection' => 'customTemplate',
    ],
]);

Add custom Twig templates (e.g., templates/custom_autocomplete.html.twig):

{# templates/custom_autocomplete.html.twig #}
<div class="custom-autocomplete">
    {{ form_widget(form) }}
    <span class="price">{{ data.price }}</span>
</div>

5. Integration with API Platform

Use the bundle with API Platform entities:

$resolver->setDefaults([
    'class' => Product::class,
    'ajax_route' => 'api_products',
    'ajax_route_parameters' => [],
    'choice_label' => 'name',
    'api_platform' => true, // Enable API Platform integration
]);

6. Lazy Loading with Pagination

Implement pagination in the autocomplete controller:

public function __invoke(Request $request, UserRepository $userRepository)
{
    $page = $request->query->getInt('page', 1);
    $limit = 10;
    $users = $userRepository->findByNamePaginated(
        $request->query->get('term'),
        $page,
        $limit
    );

    $data = array_map(function ($user) {
        return ['id' => $user->getId(), 'text' => $user->getFullName()];
    }, $users);

    return $this->json([
        'results' => $data,
        'pagination' => [
            'page' => $page,
            'last_page' => ceil($users->getTotalItems() / $limit),
        ],
    ]);
}

Update the form type to handle pagination:

$resolver->setDefaults([
    'select2_options' => [
        'ajax' => [
            'data' => function ($params) {
                return [
                    'term' => $params['term'],
                    'page' => $params['page'] ?? 1,
                ];
            },
            'processResults' => function ($data) {
                return [
                    'results' => $data['results'],
                    'pagination' => [
                        'more' => $data['pagination']['page'] < $data['pagination']['last_page'],
                    ],
                ];
            },
        ],
    ],
]);

Integration Tips

1. Symfony UX Turbo/Stimulus

Combine with Symfony UX for enhanced interactivity:

// assets/controllers/autocomplete_controller.js
import { Controller } from '@hotwired/stimulus';

export default class extends Controller {
    connect() {
        this.element.addEventListener('change', (event) => {
            // Handle selection changes
        });
    }
}

Update Twig template:

{{ form_widget(form) }}
{{ stimulus_controller('autocomplete', {'value': form.vars.value|default('')}) }}

2. Form Events

Listen to form events for dynamic updates:

$builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
    $form = $event->getForm();
    $data = $event->getData();

    if ($data) {
        $form->add('custom_field', TextType::class, [
            'data' => $data->getCustomField(),
        ]);
    }
});

3. Validation and Error Handling

Customize error messages:

$resolver->setDefaults([
    'error_bubbling' => true,
    'constraints' => [
        new NotBlank(),
        new Callback([$this, 'validateUser']),
    ],
]);

public function validateUser($value, ExecutionContextInterface $context)
{
    if ($value && !$value->isActive()) {
        $context->buildViolation('User is inactive.')
            ->atPath('user')
            ->addViolation();
    }
}

4. Server-Side Processing

Offload heavy processing to the server:

$resolver->setDefaults([
    'ajax_route' => 'user_autocomplete_processed',
    'select2_options' => [
        'ajax' => [
            'beforeSend' => function ($jqXHR, settings) {
                settings.data.push({ name: 'process', value: 'heavy' });
            },
        ],
    ],
]);

Gotchas and Tips

Pitfalls

1. CORS Issues

  • Problem: Autocomplete requests may fail due to CORS if the API and frontend are on different domains.
  • Solution: Configure CORS in Symfony:
    # config/packages/nelmio_cors.yaml
    nelmio_cors:
        defaults:
            allow_origin: ['*']
            allow_methods: ['GET', 'POST']
            allow_headers: ['Content-Type']
            expose_headers: []
            max_age: 3600
            hosts: []
            origin_regex: false
    
    Install NelmioCors
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource