Setting table columns based on model's json column

I have this structure: Form Response a form has n responses, 1 response belongs to 1 form a form has a json field called fields - example:
[{"name": "birthdate", "type": "2", "is_required": true, "placeholder": "Random placeholder test"}]
[{"name": "birthdate", "type": "2", "is_required": true, "placeholder": "Random placeholder test"}]
a response has a field called responses - example:
{"birthdate": "2023-11-25"}
{"birthdate": "2023-11-25"}
in the form's responses table, i want to set the table's columns dynamically, so it shows all form fields and their responses. im trying this: (file app/Filament/Resources/ResponseResource.php)
public static function table(Table $table): Table
{
return $table
->columns((function (): array {
$form = Form::findOrFail(1); // 1 is set hardcoded on purpose to test

return collect()
->merge($form->fields)
->map(function (array $field) {
return Tables\Columns\TextColumn::make($field['name'])
->formatStateUsing(function (Response $record) use ($field) {
return $record->responses[str($field['name'])->slug()->toString()]; // this doesnt work ⚠️
})
;
})
->merge([
Tables\Columns\TextColumn::make('created_at'),
Tables\Columns\ToggleColumn::make('is_read')
->onColor(Color::Green)
->offColor(Color::Red)
,
])
->toArray()
;
})())
public static function table(Table $table): Table
{
return $table
->columns((function (): array {
$form = Form::findOrFail(1); // 1 is set hardcoded on purpose to test

return collect()
->merge($form->fields)
->map(function (array $field) {
return Tables\Columns\TextColumn::make($field['name'])
->formatStateUsing(function (Response $record) use ($field) {
return $record->responses[str($field['name'])->slug()->toString()]; // this doesnt work ⚠️
})
;
})
->merge([
Tables\Columns\TextColumn::make('created_at'),
Tables\Columns\ToggleColumn::make('is_read')
->onColor(Color::Green)
->offColor(Color::Red)
,
])
->toArray()
;
})())
which results into this image here, where the birthdate isnt shown. why??? if i just dd $record->responses[str($field['name'])->slug()->toString()] in my tinker, it works, it shows -> "2023-11-25"
No description
7 Replies
ericmp #2
ericmp #27mo ago
if something is unclear, let me know please, so i can try to explain it better
Sergiu
Sergiu7mo ago
have you tried dd() inside the ->formatStateUsing() ?
ericmp #2
ericmp #27mo ago
yes, it doesnt dd but if i instead do it in here, when mergin the created_at field, it dds
Tables\Columns\TextColumn::make('created_at')
->formatStateUsing(function (Response $record) use ($field) {
dd('hi'); // i see it in the browser
})
,
Tables\Columns\TextColumn::make('created_at')
->formatStateUsing(function (Response $record) use ($field) {
dd('hi'); // i see it in the browser
})
,
ConnorHowell
ConnorHowell7mo ago
Try using getStateUsing instead of formatStateUsing, it won't call if the column name does not exist on the base data 'birthdate' doesn't exist on $record so it won't even attempt to call the format function as there isn't really anything to format.
ericmp #2
ericmp #27mo ago
cant believe it works u think the code looks fine? or is kinda weird? i mean, u'd do it the way i did it? just looking for some feedback now ( : , if u dont mind
ConnorHowell
ConnorHowell7mo ago
Nah I don't see anything inherently wrong with it, you could maybe store the slug as part of the fields def so you don't have to repeat this:
str($field['name'])->slug()->toString()
str($field['name'])->slug()->toString()
Just $field['slug'] or something
ericmp #2
ericmp #27mo ago
thanks (: appreciate ur help y'all