Select Component Lazy Loading though API
I use external API as the source of options for my select component.
Is there anyway to make it support the pagination of the api? which means load more data once the user scrolled to the end of shown records? either by auto calling the api and pass param page=1/2/3.. or the user click on show more button or smth' similar?
My current code:
here is how i use the component:
Select::make('general_topic_id')
->label('General topic')
->searchable()
->options(fn ($get) => $this->getGeneralTopicOptions($get, null))
->getSearchResultsUsing(fn ($get, string $search) => $this->getGeneralTopicOptions($get, $search))
->disabled(fn ($get) => !$get('org_library_access_authorization_id'))
->reactive()
->placeholder('Select a general topic'),
and here is my getGeneralTopicOptions method:
private function getGeneralTopicOptions($get, $search): array
{
$orgLibraryAccessAuthorizationId = $get('org_library_access_authorization_id');
if (empty($orgLibraryAccessAuthorizationId)) {
return [];
}
$generalTopics = ReferenceCurriculumService::getGeneralTopics($orgLibraryAccessAuthorizationId, $this->course->subject_code, $search);
return collect($generalTopics)->mapWithKeys(function ($topic) {
return [$topic['id'] => $topic['name']];
})->toArray();
}
18 Replies
Custom component I think
Hi Leandro, entirly custom? or based on a suggestion?
entirely
actually i am facing much troubles with the official docs in this regard, it's not really explaining how custom components can be structured. can you provide me with sufficient resources in this regard please?
if you want to use the blade component
https://filamentphp.com/docs/3.x/support/blade-components/select#overview
Thanks for sharing Leandro, I was trying to keep the functionality of the current Select component and extend it. I'll try to give it another try with building a custom field.
if you have any thoughts in regard to the extend methodology will be appreciated.
Hi @Leandro Ferreira,
I created this Test custom Field:
<?php
namespace App\Forms\Components;
use Filament\Forms\Components\Field;
use Filament\Forms\Components\Concerns;
class Test extends Field
{
use Concerns\HasPlaceholder;
use Concerns\HasOptions;
protected string $view = 'forms.components.test';
public function loadMoreOptions()
{
\Log::info("got called!!");
}
}
and here is my forms.components.test blade file code:
@php
$statePath = $getStatePath();
$isDisabled = $isDisabled();
$placeholder = $getPlaceholder();
$options = $getOptions();
@endphp
<x-dynamic-component
:component="$getFieldWrapperView()"
:field="$field"
:inline-label-vertical-alignment="\Filament\Support\Enums\VerticalAlignment::Center"
>
<x-filament::input.wrapper :disabled="$isDisabled">
<div
class="hidden"
x-data="{
isDisabled: @js($isDisabled),
init: function () {
const container = $el.nextElementSibling
container.dispatchEvent(
new CustomEvent('set-select-property', {
detail: { isDisabled: this.isDisabled },
}),
)
console.log(this.isDisabled);
},
}"
></div>
<div>
<select
x-ref="input"
wire:model="state.{{ $statePath }}"
style="border: none; height: 36px; line-height: 36px; border-radius: .5rem; padding-top: 0; padding-bottom: 0; width: 100%; font-size: 14px;"
{{ $isDisabled ? 'disabled' : '' }}
>
<option value="" disabled selected>{{ $placeholder }}</option>
@foreach ($options as $key => $option)
<option value="{{ $key }}">{{ $option }}</option>
@endforeach
</select>
<button type="button" wire:click="loadMoreOptions()">Load More Options</button>
</div>
</x-filament::input.wrapper>
</x-dynamic-component>
the wire:click="loadMoreOptions()"
returns Unable to call component method. Public method [loadMoreOptions] not found on component
is there a proper way to call the method? I couldn't find a suitable result while I am searching in this regard.CreatePage, EditPage, etc are the livewire components. So you should add this method in your pages
Hi @Leandro Ferreira, I created my custom component. all looks good, but i have a small issue here.
here is my form schema:
when i click 'add Unit' from the repeater, this part of the code, which loads my component is causing an issue:
$this->record ?
View::make('filament.import-lesson-material')
->viewData(['course' => $this->record])
->columnSpan('full')
: null,
i get in the broswer console:
and the repeater loses its binding to the rest of the form, so when i click submit it do net see all of the rest fields in the other repeater forms. its like corrupt everything.
the content of the filament.import-lesson-material is:
@if($course && isset($getState()['id']))
@livewire('import-lesson-material', ['course' => $course, 'lesson' => $getState()])
@endif
Can you tell what part of this work breaks the flow?Please open new topics for any issues you’re encountering.
Regarding this specific issue, I suggest reducing some of the code to better focus on the problem. Did you follow the instructions in https://filamentphp.com/docs/3.x/forms/adding-a-form-to-a-livewire-component#adding-the-form when creating your component?
yes, but it looks using it inside a repeater duplicates the main component div id which causes the issue.
@Leandro Ferreira,
my structure is in an EditRecord page > has a Repeater > uses ImportLessonMaterial extends Filament\Forms\Components\Component > in its view > I call liveware component which is a button that opens a modal.
does this structure has an issue?
my issue currently, is a dubplicated IDs as i see from the console