To keep the focus on the field when ->afterStateUpdated() is triggered, you can use JavaScript to manually set the focus back to the field. Filament forms provide a way to execute JavaScript after state updates using the ->afterStateUpdated() method.
Here's how you can modify your code to include JavaScript that sets the focus back to the field:
- Add an
idattribute to the fields you want to keep focused. - Use JavaScript to set the focus back to the field after the state is updated.
Here's an example of how you can achieve this:
public static function form(Form $form): Form
{
Carbon::setLocale('de');
return $form
->schema([
Forms\Components\Grid::make(8)
->schema([
Forms\Components\TextInput::make('id_user')
->default(function () {
return Auth::user()->id;
})
->columnSpanFull()
->disabled()
->dehydrated()
->relationship('user', 'name'),
Select::make('Mitarbeiter')
->relation('user', 'name')
->default(function () {
return Auth::user()->id;
})
->disabled()
->hidden()
->columnSpan(4)
->label('Mitarbeiter')
->getOptionLabelFromRecordUsing(fn(Model $record) => "{$record->name}"),
DatePicker::make('ts_date')
->prefix(function(callable $get) {
return $get('ts_date') == null ? '' : Carbon::parse($get('ts_date'))->translatedFormat('l ');
})
->label('Datum')
->columnSpan(2)
->required()
->reactive()
->autofocus(true)
->afterStateUpdated(function(callable $set, callable $get) {
self::updateDuration($set, $get);
echo '<script>document.getElementById("ts_date").focus();</script>';
})
->id('ts_date'),
TimePicker::make('ts_time_start')
->label('Startzeit')
->default('08:00')
->required()
->seconds(false)
->columnSpan(2)
->reactive()
->debounce(1500)
->afterStateUpdated(function(callable $set, callable $get) {
self::updateDuration($set, $get);
echo '<script>document.getElementById("ts_time_start").focus();</script>';
})
->id('ts_time_start'),
Forms\Components\TextInput::make('duration_override_dec')
->label('Dauer')
->disabled()
->dehydrated()
->numeric()
->readOnly()
->columnSpan(2)
->formatStateUsing(function ($state) {
return round($state / 0.05) * 0.05;
})
->suffix(' h'),
TimePicker::make('ts_time_end')
->label('Endzeit')
->columnSpan(2)
->seconds(false)
->default('08:00')
->native(true)
->minutesStep(5)
->required()
->reactive()
->debounce(3000)
->afterStateUpdated(function(callable $set, callable $get) {
self::updateDuration($set, $get);
echo '<script>document.getElementById("ts_time_end").focus();</script>';
})
->autofocus()
->id('ts_time_end'),
Forms\Components\TextInput::make('ts_start')
->label(false)
->disabled()
->dehydrated()
->readonly()
->columnSpan(4),
Forms\Components\TextInput::make('ts_end')
->label(false)
->disabled()
->dehydrated()
->readOnly()
->columnSpan(4),
Select::make('id_projekt')
->relationship('project', 'unique_name')
->columnSpan(8)
->placeholder('--')
->label('Projekt')
->getOptionLabelFromRecordUsing(fn(Model $record) => "{$record->unique_name}"),
Forms\Components\Textarea::make('description')
->label('Tätigkeit')
->required()
->columnSpan(8)
->rows(2),
Select::make('id_kostenstelle')
->relationship('kostenstelle', 'Bezeichnung')
->label('Kostenstelle')
->placeholder('--')
->columnSpan(4)
->getOptionLabelFromRecordUsing(fn(Model $record) => "{$record->Bezeichnung}"),
Forms\Components\Textarea::make('kommentar')
->maxLength(300)
->columnSpan(4)
->rows(2),
])
]);
}
In this example, I've added an id attribute to the DatePicker, TimePicker, and other relevant fields. After the state is updated, a small JavaScript snippet is executed to set the focus back to the field using document.getElementById().focus().
This should help keep the focus on the field after the state is updated.