nova-issues
nova-issues copied to clipboard
Repeater styling
- Laravel Version: 10.41.0
- Nova Version: 4.32.11
- PHP Version: 8.1
Description:
Is it normal that the repeater trash icon is not uniform with the rest of nova ?
Also, my field is shown in the edit view and save just fine.
Repeater::make(__('Links'), 'links')
->repeatables([
\App\Nova\Repeater\ProjectLink::make()->confirmRemoval(),
])->asJson(),
But is it normal that my field is not shown in the detail view ?
The ->confirmRemoval()
does not appear to do anything either 🤔
Having the same, seems weird it does not show anything when viewing the resource detail page. It should display an overview of the line items.
@Navi2016 Yeah I opened a PR to the docs, but they don't seem to care: https://github.com/laravel/nova-docs/pull/570.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Not stale
@Navi2016 Yeah I opened a PR to the docs, but they don't seem to care: laravel/nova-docs#570.
I don't think it's a matter of not caring - it's not apparent from that pull request that you're wanting the repeater details to display in the detail view.
Which BTW I would like to see also
@sp4cecat The doc PR was to inform that the component was for display only but they closed it and didn't add any info about this in the doc
Text::make('Item content', 'line_items', function ($value, $resource, $attribute) {
if ($value) {
$value = json_decode($value);
$arr = [];
foreach ($value as $item) {
$arr[] = $item->fields->item_content;
}
return implode("
", $arr);
}
})->asHtml();
Text::make('Item content', 'line_items', function ($value, $resource, $attribute) { if ($value) { $value = json_decode($value); $arr = []; foreach ($value as $item) { $arr[] = $item->fields->item_content; } return implode("", $arr); } })->asHtml();
Thanks for having a crack :)
jsondecode is not needed if you've cast the repeated field in your model file, ie:
protected $casts = [
'line_items' => 'array',
];
And also the individual line item structure is a bit more complex than that -
- type (string)
- fields (array)
\
[key, value]...
Any Update/Roadmap on this?
Ive made a quick Shortcut where one can pass a Repeater to view it on Detail:
Usage:
Panel::make('Panel', [
...RepeaterDetailView::makeBoth(Repeater::make('Label', 'attribute'), $request)
]);
app/Nova/Fields/RepeaterDetailView.php
<?php
namespace App\Nova\Fields;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
use Laravel\Nova\Fields\Field;
use Laravel\Nova\Fields\Hidden;
use Laravel\Nova\Fields\Repeater;
use Laravel\Nova\Fields\Text;
use Laravel\Nova\Http\Requests\NovaRequest;
class RepeaterDetailView {
public static function makeBoth(Repeater $repeater, NovaRequest $request): array {
return [
$repeater,
self::make($repeater, $request)
];
}
public static function make(Repeater $repeater, NovaRequest $request): Text {
return Text::make(
$repeater->name, function (Model $model) use ($repeater, $request): string {
$items = $model->{$repeater->attribute};
if (is_null($items)) return '';
$tables = [];
foreach ($items as $item) {
$type = $repeater->repeatables->findByKey($item['type']);
/** @var Collection<Field> $fields */
$fields = $type->fields($request);
$table = [
'headers' => [],
'rows' => [[]]
];
foreach ($fields as $field) {
if ($field instanceof Hidden) continue;
$table['headers'][] = $field->name;
$table['rows'][0][] = $item['fields'][$field->attribute];
}
$tables[] = $table;
}
return implode(
'<br />',
array_map(
fn(array $table) => view('partials.table',
$table
)->render(),
$tables
)
);
})->onlyOnDetail()->asHtml();
}
}
table.partials.php
<table class="table w-full divide-y divide-gray-100 dark:divide-gray-700 mb-6">
<thead>
<tr>
@foreach($headers as $header)
<th>{{$header}}</th>
@endforeach
</tr>
</thead>
<tbody class="divide-y divide-gray-100 dark:divide-gray-700">
@foreach($rows as $row)
<tr class="table-row">
@foreach($row as $cell)
<td class="">
{{ $cell }}
</td>
@endforeach
</tr>
@endforeach
</tbody>
</table>
This wasn't obvious for me, so posting for other who also might struggle with this issue.
Basically in your Nova/Resource file you can have both Repeater and HasMany:
Repeater::make('Line Items')
->repeatables([
\App\Nova\Repeater\LineItem::make()
])
->asHasMany()
->showOnDetail(),
HasMany::make('Line Items'),
However for some unknown reason, each calls a different functions in Model:
Repeater::make('Line Items') calls line_items()
but
HasMany::make('Line Items') calls lineItems()
You can however mitigate that by a few more arguments:
HasMany::make('Line Items', 'line_items', \App\Nova\LineItem::class),
This way you will see Repeater editor while editing and table view of when viewing.
I would also like to see the JSON column details on the resource page as mentioned in https://github.com/laravel/nova-issues/issues/6166#issuecomment-1909396838 by @mrleblanc101
+1
Not totally sure if I just stack below this issue, but the name of the issue is 'Repeater styling' so here I go. I am trying to use the Repeater field as a block builder, but the select when having multiple repeaterables isn't that UX friendly.
When having multiple types of repeatables the vue swaps to Dropdownmenu instead of InvertedButton. Only the DropdownMenu inside of the RepeaterField.vue is missing a width defination or the fallback width value of the DropdownMenu should be 'auto'.
In the current situation when nothing is defined it will be fixed to 120px. Which isn't a lot with also the icon before, and leaving therefor only space for about 7 character as label.