Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PROPOSITION NEW FEATURE] Select2 with data list obtained via AJAX #80

Open
shawe opened this issue Aug 20, 2024 · 1 comment
Open

[PROPOSITION NEW FEATURE] Select2 with data list obtained via AJAX #80

shawe opened this issue Aug 20, 2024 · 1 comment

Comments

@shawe
Copy link

shawe commented Aug 20, 2024

This is not an issue of an error.

May it be possible to implement filters that are populated via AJAX, as documented for Select2, so that large amounts of data can be used, but without negatively affecting the user experience?

I have some working on editing small forms, and I think this way would be good for certain cases where some filters could have a lot of data but its populated on demand when needed.

I can share this with you, or colaborate with your repo to add this support if you are interested.

I do it this way to have an initial support outside laravel livewire tables, and seems to be responsiveness. But not in laravel liverwire tables, an looking for a possible existing filter found your repo, and I think that could be a good extra for your advanced filters. But maybe not implement as I'm sharing with you to can have any usable samples.

  • The default selected items, are auto-loaded with an AJAX call by ID.
  • The others items are loaded with a preview of APP_PAGINATION items, and you can write to get other items, and scroll down to load more pages.

For example:

  • Admin route:
Route::get('users/json/{search?}', [UserController::class, 'json'])->name('admin.users.json');
  • Admin Controller: app/Http/Controllers/Admin/UserController.php
    /**
     * Get users as JSON.
     *
     * @param string $search
     * @return JsonResponse
     */
    public function json(string $search = ''): JsonResponse
    {
        if (empty($search)) {
            $search = request()->input('term');
        }
        $items = DB::table(User::getTableName())
            ->select('id AS id', 'name AS text')
            ->where('name', 'like', '%' . $search . '%')
            ->orWhere('id', $search)
            ->orderBy('name')
            ->paginate(env('APP_PAGINATION', 10), ['*'], 'page', request()->input('page', 1));
        return response()->json([
            'pagination' => [
                'more' => $items->hasMorePages(),
                'last_page' => $items->lastPage(),
                'current_page' => $items->currentPage(),
            ],
            'results' => $items->items(),
        ]);
    }
  • Select component: resources/views/components/form/select.blade.php
<div class="form-group">
    {!! Form::label($name, $label, ['class' => 'control-label fw-bold']) !!}
    @php
        $attrs = $attrs ?? [];
        if(isset($placeholder)) {
            $attrs = array_merge(['placeholder' => $placeholder ?? ''], $attrs);
        }
        if (in_array('multiple', $attrs)) {
            $name = preg_match('/\[\]$/', $name) ? $name : $name . '[]';
        }
        $options = array_merge(['' => __('Select one item')], $options ?? []);
    @endphp
    {!! Form::select($name, $options, $value, array_merge(['class' => 'form-select select2'], $attrs)); !!}
    @error($name)
        <span class="text-danger">{{ $message }}</span>
    @enderror
</div>

@once
    @push('css')
        <link rel="stylesheet" href="{{ asset('build/extensions/select2/css/select2.min.css') }}">
        <link rel="stylesheet"
              href="{{ asset('build/extensions/select2-bootstrap-5-theme/select2-bootstrap-5-theme.min.css') }}">
    @endpush

    @push('js')
        <script src="{{ asset('build/extensions/select2/js/select2.min.js') }}"></script>
        @if (file_exists(public_path('build/extensions/select2/js/i18n/' . app()->getLocale() . '.js')))
            <script src="{{ asset('build/extensions/select2/js/i18n/' . app()->getLocale() . '.js') }}"></script>
        @endif
    @endpush
@endonce

@push('js')
    <script>
        $(document).ready(function () {
            $('#{{ $id }}').select2({
                theme: 'bootstrap-5',
                width: $(this).data('width') ? $(this).data('width') : $(this).hasClass('w-100') ? '100%' : 'style',
                closeOnSelect: false,
                placeholder: {
                    id: '-1', // the value of the option
                    text: '{{ __('Select one item') }}'
                },
                @if (in_array('multiple', $attrs))
                    cache: true,
                    tags: true,
                    allowClear: true,
                    tokenSeparators: [',', ' '],
                @endif
                @if ($url)
                ajax: {
                    url: '{{ $url }}',
                    dataType: 'json',
                    delay: 250,
                    data: function (params) {
                        return {
                            term: params.term || '',
                            page: params.page || 1
                        };
                    },
                    processResults: function(data, params) {
                        params.page = params.page || 1;

                        return {
                            results: data.results,
                            pagination: {
                                more: data.pagination.last_page != params.page
                            }
                        };
                    },
                    cache: true,
                },
                @endif
            });

            {{-- INSERT DATA BY DEFAULT --}}
            @if (!empty($value))
                let itemSelect = $('#{{ $id }}');
                {{-- INSERT SINGLE DATA --}}
                @if (is_string($value))
                    $.ajax({
                        type: 'GET',
                        url: '{{ $url . '/' . $value }}',
                    }).then(function (data) {
                        data = data.results.length > 0 ? data.results[0] : data.results;
                        var option = new Option(data.text, data.id, true, true);
                        itemSelect.append(option).trigger('change');
                    });
                @endif
                {{-- INSERT MULTIPLE DATA --}}
                @if (is_array($value))
                    @foreach($value as $item_id)
                        $.ajax({
                            type: 'GET',
                            url: '{{ $url . '/' . $item_id }}',
                        }).then(function (data) {
                            data = data.results.length > 0 ? data.results[0] : data.results;
                            var option = new Option(data.text, data.id, true, true);
                            itemSelect.append(option).trigger('change');
                        });
                    @endforeach
               @endif
            @endif
        });
    </script>
@endpush
@shawe
Copy link
Author

shawe commented Aug 20, 2024

If you can share with me some guidelines, I can try to implemented it more clean to your repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant