Can I have dynamic columns or inputs in resource?

I have a model that has a json column with key value pairs. However the keys are not constant and generated by user input. Is it possible to have one text column per entry? I was thinking something like this but PHP doesn't like it:
return $table
->columns([
TextColumn::make('id')->label('Proposal ID'),
TextColumn::make('status'),
TextColumn::make('name'),
...function ($record): array {
return $record->answers->map(function ($answer) {
return TextColumn::make($answer);
});
},
])
...
return $table
->columns([
TextColumn::make('id')->label('Proposal ID'),
TextColumn::make('status'),
TextColumn::make('name'),
...function ($record): array {
return $record->answers->map(function ($answer) {
return TextColumn::make($answer);
});
},
])
...
6 Replies
Dennis Koch
Dennis Koch15mo ago
Dynamic columns aren’t a problem. But since the amount of answers vary per record it’s harder You could try getting the max value of answers. Loop the number and add a column for every answer TextColumn::make('answer.0') and so on. Maybe you need getStateUsing() to prevent undefined array keys.
techenby
techenby15mo ago
Since it's in a relationship manager, it wouldn't vary per record. The values for the potential keys are stored in the parent, but how do I loop through an array to generate many TextColumn(s) Like normally I'd foreach over $this->record but only being able to access the owner record in a closure makes it confusing, and makes my brain melt a little bit
Dennis Koch
Dennis Koch15mo ago
If it doesn’t vary per record, why do you need to access $this->record then?
techenby
techenby15mo ago
It varies per parent, maybe if I add more context lol. I have a survey model, that folks can build up a form for users to fill out. What I'm working on now is displaying the answers to the survey questions in a table. Depending on which survey I click into, the ids for the user's answer can vary a lot. So I'm trying to iterate over the questions and get the answer and put it into a column. I hope that makes sense 😬 Here's a gist with example data: https://gist.github.com/techenby/eec1531522f1c6f37819c0915e1be9bf I'm working on a ResponsesRelationshipManager that is on the SurveyResource and I'd like to have a column for favorite-color and favorite-cake I can iterate over each item in the answers column or iterate over the ids grabbed from the Survey. But that still leads me to two questions: 1: how to foreach or map over a value to get n number of columns 2. How to get the $record or $ownerRecord to pass into the foreach or map (Eventually I'd like to use FormBuilder to dynamically generate the form on the frontend but that's a project for a different day) I was able to accomplish what I wanted, but I'm not super happy with it. I'm using the uri of the request to figure out what model I'm looking at and fetch what I need.
public static function getFormColumns()
{
$uri = request()->getRequestUri();
if (Str::of($uri)->startsWith('/livewire')) {
$data = request()->json()->get('serverMemo')['dataMeta']['models'];
$id = isset($data['record']) ? $data['record']['id'] : $data['ownerRecord']['id'];
} else {
$id = explode('/', $uri)[3];
}
$form = ModelsForm::where('event_id', $id)->where('type', 'workshop')->first();

if ($form) {
return collect($form->settings->searchable)
->map(function ($id) {
return TextColumn::make('answers.' . $id)
->label(strtoupper($id))
->toggleable();
});
}
}
public static function getFormColumns()
{
$uri = request()->getRequestUri();
if (Str::of($uri)->startsWith('/livewire')) {
$data = request()->json()->get('serverMemo')['dataMeta']['models'];
$id = isset($data['record']) ? $data['record']['id'] : $data['ownerRecord']['id'];
} else {
$id = explode('/', $uri)[3];
}
$form = ModelsForm::where('event_id', $id)->where('type', 'workshop')->first();

if ($form) {
return collect($form->settings->searchable)
->map(function ($id) {
return TextColumn::make('answers.' . $id)
->label(strtoupper($id))
->toggleable();
});
}
}
Then in the table I have this:
return $table
->columns([
TextColumn::make('id')->label('Proposal ID'),
TextColumn::make('status'),
TextColumn::make('name'),
...static::getFColumns(),
])
return $table
->columns([
TextColumn::make('id')->label('Proposal ID'),
TextColumn::make('status'),
TextColumn::make('name'),
...static::getFColumns(),
])
I'd still love to hear someone else's take on if there's a better way to do this.
techenby
techenby15mo ago
Dan Harrin
Dan Harrin15mo ago
try defining getTableColumns() instead, which is not a static method. you can use $this->ownerRecord you can leave out the $table->columns() if you define that