Repeaters... How to feed them custom data?

So below i have the following code which reports the following display. I cannot use relationships on the "front end" due to how we are using tennants
No description
24 Replies
AreYouScared
AreYouScaredOP5mo ago
Forms\Components\Repeater::make('server_variables')
->relationship('serverVariables')
->grid()
->mutateRelationshipDataBeforeSaveUsing(function (array &$data): array {
foreach ($data as $key => $value) {
if (!isset($data['variable_value'])) {
$data['variable_value'] = '';
}
}

return $data;
})
->reorderable(false)->addable(false)->deletable(false)
->schema(function () {

$text = Forms\Components\TextInput::make('variable_value')
->hidden($this->shouldHideComponent(...))
->required(fn (ServerVariable $serverVariable) => in_array('required', explode('|', $serverVariable->variable->rules)))
->rules([
fn (ServerVariable $serverVariable): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
$validator = Validator::make(['validatorkey' => $value], [
'validatorkey' => $serverVariable->variable->rules,
]);

if ($validator->fails()) {
$message = str($validator->errors()->first())->replace('validatorkey', $serverVariable->variable->name);

$fail($message);
}
},
]);

$select = Forms\Components\Select::make('variable_value')
->hidden($this->shouldHideComponent(...))
->options($this->getSelectOptionsFromRules(...))
->selectablePlaceholder(false);

$components = [$text, $select];

foreach ($components as &$component) {
$component = $component
->live(onBlur: true)
->hintIcon('tabler-code')
->label(fn (ServerVariable $serverVariable) => $serverVariable->variable->name)
->hintIconTooltip(fn (ServerVariable $serverVariable) => $serverVariable->variable->rules)
->prefix(fn (ServerVariable $serverVariable) => '{{' . $serverVariable->variable->env_variable . '}}')
->helperText(fn (ServerVariable $serverVariable) => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description);
}

return $components;
})
->columnSpan(6),
Forms\Components\Repeater::make('server_variables')
->relationship('serverVariables')
->grid()
->mutateRelationshipDataBeforeSaveUsing(function (array &$data): array {
foreach ($data as $key => $value) {
if (!isset($data['variable_value'])) {
$data['variable_value'] = '';
}
}

return $data;
})
->reorderable(false)->addable(false)->deletable(false)
->schema(function () {

$text = Forms\Components\TextInput::make('variable_value')
->hidden($this->shouldHideComponent(...))
->required(fn (ServerVariable $serverVariable) => in_array('required', explode('|', $serverVariable->variable->rules)))
->rules([
fn (ServerVariable $serverVariable): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
$validator = Validator::make(['validatorkey' => $value], [
'validatorkey' => $serverVariable->variable->rules,
]);

if ($validator->fails()) {
$message = str($validator->errors()->first())->replace('validatorkey', $serverVariable->variable->name);

$fail($message);
}
},
]);

$select = Forms\Components\Select::make('variable_value')
->hidden($this->shouldHideComponent(...))
->options($this->getSelectOptionsFromRules(...))
->selectablePlaceholder(false);

$components = [$text, $select];

foreach ($components as &$component) {
$component = $component
->live(onBlur: true)
->hintIcon('tabler-code')
->label(fn (ServerVariable $serverVariable) => $serverVariable->variable->name)
->hintIconTooltip(fn (ServerVariable $serverVariable) => $serverVariable->variable->rules)
->prefix(fn (ServerVariable $serverVariable) => '{{' . $serverVariable->variable->env_variable . '}}')
->helperText(fn (ServerVariable $serverVariable) => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description);
}

return $components;
})
->columnSpan(6),
On the "front end" i had to use a Section instead of the repeater...
Section::make('Server Variables')
->columnSpanFull()
->columns([
'default' => 1,
'lg' => 2,
])
->schema(function () {
/** @var Server $server */
$server = Filament::getTenant();
$variableComponents = [];

/** @var ServerVariable $serverVariable */
foreach ($server->serverVariables->sortBy(fn ($serverVariable) => $serverVariable->variable->sort) as $serverVariable) {
if (!$serverVariable->variable->user_viewable) {
continue;
}

$text = TextInput::make($serverVariable->variable->name)
->hidden(fn (Component $component) => $this->shouldHideComponent($serverVariable, $component))
->disabled(fn () => !$serverVariable->variable->user_editable)
->required(fn () => in_array('required', explode('|', $serverVariable->variable->rules)))
->rules([
fn (): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
$validator = Validator::make(['validatorkey' => $value], [
'validatorkey' => $serverVariable->variable->rules,
]);

if ($validator->fails()) {
$message = str($validator->errors()->first())->replace('validatorkey', $serverVariable->variable->name);

$fail($message);
}
},
]);

$select = Select::make($serverVariable->variable->name)
->hidden(fn (Component $component) => $this->shouldHideComponent($serverVariable, $component))
->disabled(fn () => !$serverVariable->variable->user_editable) // TODO: find better way, doesn't look so nice
->options(fn () => $this->getSelectOptionsFromRules($serverVariable))
->selectablePlaceholder(false);

$components = [$text, $select];

foreach ($components as &$component) {
$component = $component
->live(onBlur: true)
->afterStateUpdated(function ($state) use ($serverVariable) {
$this->update($state, $serverVariable->variable->env_variable);
})
->hintIcon('tabler-code')
->label(fn () => $serverVariable->variable->name)
->default(fn () => $serverVariable->variable_value ?? $serverVariable->variable->default_value)
->hintIconTooltip(fn () => $serverVariable->variable->rules)
->prefix(fn () => '{{' . $serverVariable->variable->env_variable . '}}')
->helperText(fn () => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description);
}

$variableComponents = array_merge($variableComponents, $components);
}

return $variableComponents;
}),
]);
Section::make('Server Variables')
->columnSpanFull()
->columns([
'default' => 1,
'lg' => 2,
])
->schema(function () {
/** @var Server $server */
$server = Filament::getTenant();
$variableComponents = [];

/** @var ServerVariable $serverVariable */
foreach ($server->serverVariables->sortBy(fn ($serverVariable) => $serverVariable->variable->sort) as $serverVariable) {
if (!$serverVariable->variable->user_viewable) {
continue;
}

$text = TextInput::make($serverVariable->variable->name)
->hidden(fn (Component $component) => $this->shouldHideComponent($serverVariable, $component))
->disabled(fn () => !$serverVariable->variable->user_editable)
->required(fn () => in_array('required', explode('|', $serverVariable->variable->rules)))
->rules([
fn (): Closure => function (string $attribute, $value, Closure $fail) use ($serverVariable) {
$validator = Validator::make(['validatorkey' => $value], [
'validatorkey' => $serverVariable->variable->rules,
]);

if ($validator->fails()) {
$message = str($validator->errors()->first())->replace('validatorkey', $serverVariable->variable->name);

$fail($message);
}
},
]);

$select = Select::make($serverVariable->variable->name)
->hidden(fn (Component $component) => $this->shouldHideComponent($serverVariable, $component))
->disabled(fn () => !$serverVariable->variable->user_editable) // TODO: find better way, doesn't look so nice
->options(fn () => $this->getSelectOptionsFromRules($serverVariable))
->selectablePlaceholder(false);

$components = [$text, $select];

foreach ($components as &$component) {
$component = $component
->live(onBlur: true)
->afterStateUpdated(function ($state) use ($serverVariable) {
$this->update($state, $serverVariable->variable->env_variable);
})
->hintIcon('tabler-code')
->label(fn () => $serverVariable->variable->name)
->default(fn () => $serverVariable->variable_value ?? $serverVariable->variable->default_value)
->hintIconTooltip(fn () => $serverVariable->variable->rules)
->prefix(fn () => '{{' . $serverVariable->variable->env_variable . '}}')
->helperText(fn () => empty($serverVariable->variable->description) ? '—' : $serverVariable->variable->description);
}

$variableComponents = array_merge($variableComponents, $components);
}

return $variableComponents;
}),
]);
AreYouScared
AreYouScaredOP5mo ago
And the output looks like this. I would like to use the repeater as it has a better look. Anyway i can feed it custom data and not use the relationships?
No description
awcodes
awcodes5mo ago
Why do you need a repeater for this. The same layout can be accomplished with a section or even just a grid layout component. All layout component support relationships.
AreYouScared
AreYouScaredOP5mo ago
I guess I'm not understanding. Well we have an admin panel, and a "regular" panel i guess or "app" for the front end thats using Tenants, When i do ->relationship('serverVariables') we get Call to a member function serverVariables() on null
AreYouScared
AreYouScaredOP5mo ago
I'd like them to be formatted like the Repeater does, where they're in their own container boxes.
No description
AreYouScared
AreYouScaredOP5mo ago
I guess the proper term would be styled, not formatted.
awcodes
awcodes5mo ago
Fair. Just seems odd to use a repeater that doesn’t repeat. 😀
AreYouScared
AreYouScaredOP5mo ago
wdym? The repeater works as intended on the admin panel.
awcodes
awcodes5mo ago
I would say if you’re getting the null message it’s because on the front end the record isn’t being set in mount or passed to the form. The error is saying that the record is null.
AreYouScared
AreYouScaredOP5mo ago
Right, we are setting the "server" with
/** @var Server $server */
$server = Filament::getTenant();
/** @var Server $server */
$server = Filament::getTenant();
On the admin side, the record is the server.
awcodes
awcodes5mo ago
And the front end is outside of the panel in its own livewire component?
AreYouScared
AreYouScaredOP5mo ago
Its it's "own" panel? not sure how to explain it. Like the admin panel is /app/Filament/ then the "front end" is /app/Filament/App So we have two "PanelProviders" ones called Admin other called App
awcodes
awcodes5mo ago
Hmm. Then I would expect it to be fine.
AreYouScared
AreYouScaredOP5mo ago
If you're bored... its all in this repo... https://github.com/pelican-dev/panel/tree/issue/353
awcodes
awcodes5mo ago
And where should I be looking?
AreYouScared
AreYouScaredOP5mo ago
https://github.com/pelican-dev/panel/blob/issue/353/app/Filament/App/Pages/Startup.php#L78-L140 Is the file in question on the "App" the one that has no record/resource Could we get the resource/record from the url? the servers has a server_id column and its in the url, so /app/3/startup is server with the server_id of 3
awcodes
awcodes5mo ago
Ah, ok. Yea, simple page isn’t going to automatically set the record like the EditRecord class does. Have a look at how it’s being done in the EditRecord class. That should give you some insight. The SimplePage is still just a livewire component so following this should help you to get there. https://filamentphp.com/docs/3.x/forms/adding-a-form-to-a-livewire-component#setting-a-form-model
awcodes
awcodes5mo ago
You shouldn’t need to get the record inside each of the field formatStateUsing() methods. It should be set in the mount then passed to the $form->model() method.
AreYouScared
AreYouScaredOP5mo ago
Okay. Im not the one whom made the "simple" pages and everything. My scope of programming and how filament works is more of a going with the flow. Okay, i'll pass it on to the other guys and we can see what we can figure out, thanks!
awcodes
awcodes5mo ago
No worries. Just trying to give you some direction.
AreYouScared
AreYouScaredOP5mo ago
Following that page, I've added
->statePath('data')
->model($this->server)
->statePath('data')
->model($this->server)
and when adding public Post $post; above the form function i get this
No description
awcodes
awcodes5mo ago
It has to be inside the class
AreYouScared
AreYouScaredOP5mo ago
Object of class Valet\Server could not be converted to string I might just leave it alone, getting deep into the "idk what im doing" territory
awcodes
awcodes5mo ago
Ok, if it’s looking for Valet\Server then there’s definitely something you’re doing wrong. Just report back what I shared and go from there.
Want results from more Discord servers?
Add your server