How can I call a Repeaters field 'add' action on enter in field?

I know this is probably not good UX as 'Enter' should submit the form. But I have a repeater with 2 fields per row, and when pressing ENTER in the last field (qty) I'd like to add a new empty line to the repeater. How could I do that? I have now modified the Repeater's addAction using keyBindings, which kind of works but I want it to .focus on the first field on the next line. Is that even possible or how would I go about that? I have been fiddling with custom actions but no luck getting them to work. If anybody could help me I would be grateful. Thank you! Repeater code:
Repeater::make('products')->schema([
Select::make('product'),
TextInput::make('qty')
->numeric()
->step(1)
->minValue(0)
->required()
->minItems(1)
->hiddenLabel()
->addAction(
fn(\Filament\Forms\Components\Actions\Action $action) => $action->keyBindings('enter')
)
->addActionLabel(__('actions.add_line'))
->reorderable(false)
]);
Repeater::make('products')->schema([
Select::make('product'),
TextInput::make('qty')
->numeric()
->step(1)
->minValue(0)
->required()
->minItems(1)
->hiddenLabel()
->addAction(
fn(\Filament\Forms\Components\Actions\Action $action) => $action->keyBindings('enter')
)
->addActionLabel(__('actions.add_line'))
->reorderable(false)
]);
ps I've "disabled" the default submit functions using the method mentioned here: https://github.com/filamentphp/filament/discussions/6067#discussioncomment-8036673
GitHub
Prevent form submit on Enter · filamentphp filament · Discussion ...
Is there a solution that prevents submitting a form when pressing enter on a text box? Currently I couldn't find one, so this is what I came up: I created copies for create-record.blade.php and...
1 Reply
jelmerkeij
jelmerkeijOP7h ago
I realised that putting the keybind there catches it on the whole form while it should only fire when the 'qty' textfield is focused. I've now turned things around. In CreateOrder page:
public function repeaterAddLineAction(): Action
{
return Action::make('repeaterAddLine')
->action(function (array $arguments) {
$this->mountFormComponentAction('data.products', 'add');
});
}
public function repeaterAddLineAction(): Action
{
return Action::make('repeaterAddLine')
->action(function (array $arguments) {
$this->mountFormComponentAction('data.products', 'add');
});
}
On the qty TextInput:
TextInput::make('qty')
->numeric()
->step(1)
->minValue(0)
->required()
->extraAttributes(['wire:keydown.enter' => "mountAction('repeaterAddLine')"])
->label(__('labels.quantity'))
TextInput::make('qty')
->numeric()
->step(1)
->minValue(0)
->required()
->extraAttributes(['wire:keydown.enter' => "mountAction('repeaterAddLine')"])
->label(__('labels.quantity'))
While this works to add a new line to the repeater I can't get it focused on the first product field. I can call focus() from Javascript on the Products selectlist on the newly added repater line but that doesn't expand the selectlist's search and focus on the search field. Anything I can do to make that happen? I have the focussing "kinda" working when mofiying the addAction()->after() on the Repeater component:
->addAction(
fn(\Filament\Forms\Components\Actions\Action $action) => $action->after(
function (Get $get, Repeater $component) use ($form) {
// Get the newly added key of the product field
$state = $component->getState();
$items = collect($state);
$newKey = $items->keys()->last();

// Timeout to make sure the new select is on screen and then click it using JS
$selector = '#data\\\.products\\\.'.$newKey.'\\\.product';
$form->getLivewire()->js('setTimeout(()=>document.querySelector(\''.$selector.'\').click(),200)');
}
)
)
->addAction(
fn(\Filament\Forms\Components\Actions\Action $action) => $action->after(
function (Get $get, Repeater $component) use ($form) {
// Get the newly added key of the product field
$state = $component->getState();
$items = collect($state);
$newKey = $items->keys()->last();

// Timeout to make sure the new select is on screen and then click it using JS
$selector = '#data\\\.products\\\.'.$newKey.'\\\.product';
$form->getLivewire()->js('setTimeout(()=>document.querySelector(\''.$selector.'\').click(),200)');
}
)
)
This probably isn't the best solution so if anybody has a better one please let me know!

Did you find this page helpful?