Open arneau opened 1 year ago
Any update here? same happening for me
It is still not resolved, can't save image in repeatable after first save. Also, when saving two images in repeatable, the same error
Any updates or timeline on this?
Bouncing this, just purchased a new Nova license and this still seems to be a bug
Absolutely not a final solution but I've searched where the issue was and it's kind of complex.
My use case is using the JSON preset and to me, the issue come from the fact that a clean Fluent is created inside of the preset, meaning that the File field can't keep track of a precedent eventual value of the data.
ATM for those who really need to keep files data after an update request, I've found this temporary solution:
I created a custom File
field and JSON
preset to modify these few lines
// In JSON::set method, replace the $callbacks variable initialization by this one
$callbacks = $fields
->withoutUnfillable()
->withoutMissingValues()
->map(function (Field $field) use ($model, $attribute, $request, $requestAttribute, $data, $blockKey) {
$originalAttribute = $model->getOriginal($attribute);
if (!is_null($originalAttribute) && isset($originalAttribute[$blockKey])) {
$field->resolve($originalAttribute[$blockKey]['fields'], $field->attribute);
}
return $field->fillInto($request, $data, $field->attribute, "{$requestAttribute}.{$blockKey}.fields.{$field->attribute}");
})
->filter(function ($callback) {
return is_callable($callback);
});
// In File::fillAttribute method, move up the $hasExistingFile initialization and add this condition
protected function fillAttribute(NovaRequest $request, $requestAttribute, $model, $attribute)
{
// This line was just moved from a later section of the method to be used earlier
$hasExistingFile = ! is_null($this->getStoragePath());
if (is_null($file = $this->retrieveFileFromRequest($request, $requestAttribute))) {
// Add this condition to fill the attribute from the initial now-known value
if ($hasExistingFile) {
return $model->{$attribute} = $this->getStoragePath();
}
return;
}
// Leave the rest unchanged
I've created a gist here to see the full code example. Please share if you succeed further than me :)
This adds more support for the File
field and if needed you can override its descendant to make extends your File field class for Audio
, Image
, Avatar
and so on... as needed.
If you dont want to override a bunch of classes, you can even make this fix "like native" with this composer trick to load your File and JSON preset instead of the vendor one.
You won't lose your file paths on updating anymore, but there is remaining cons to this temporary solution:
null
value will resolve to the previous value instead, but you can delete the row, save the form and repopulate the row fields.null
values for the files, each file will be resolved from its previous position in the model attribute. Moving the first row to the second will move the other fields (number, text, etc..) but will keep the file at their initial position.Hoping that get fixed by a proper solution quickly 🤞🏻.
Here is my approach, which doesn't require modifying other files and may even be easy to integrate in the framework:
Add a hidden field to your Repeatable:
Hidden::make('Key') ->default(fn () => uniqid()),
In your model, do something on the lines of `protected static function boot() { parent::boot();
static::updating(function ($model) {
$originalDocuments = Arr::keyBy($model->getOriginal('documents'), 'fields.key');
$model->documents = Arr::map($model->documents, function ($document) use ($originalDocuments) {
if (! empty($document['fields']['file'])) {
return $document;
}
if (! isset($originalDocuments[$document['fields']['key']])) {
return $document;
}
$document['fields']['file'] = $originalDocuments[$document['fields']['key']]['fields']['file'] ?? '';
return $document;
});
});
}`
This assumes my DB json field is called documents, and my repeatable has a file field called "file", which I want to retain. As it probably is obvious, I am using those generated keys to put back the file paths, when updating the model.
Fixed by this section Link
just add ->uniqueField('id')
Repeater::make('Line Items')
->asHasMany()
->uniqueField('id')
->repeatables([
\App\Nova\Repeater\LineItem::make()
])
and add ID::hidden(), // The unique ID field
Fixed by this section Link
just add ->uniqueField('id')
Repeater::make('Line Items') ->asHasMany() ->uniqueField('id') ->repeatables([ \App\Nova\Repeater\LineItem::make() ])
and add ID::hidden(), // The unique ID field
This is working perfect, thanks!
Fixed by this section Link
just add ->uniqueField('id')
Repeater::make('Line Items') ->asHasMany() ->uniqueField('id') ->repeatables([ \App\Nova\Repeater\LineItem::make() ])
and add ID::hidden(), // The unique ID field
Agree that this works when using a distinct model via the asHasMany()
method, but the issue still persists when storing the data as JSON. For example, my model has an images
JSON column, and the repeater allows the storage of path
, caption
, and alt_text
fields.
Looks like I have the same problem: #6410
Any ETA on this?
Hi @tonnyorg, we are working on the next version, Nova 5 which will contain this fix. No set ETA yet but very soon, which is why we decided not to add beta related fixes to 4👍
@jeremynikolic ahhh got it, tyvm!
Description:
As per this issue's title, it appears as though Image field "values", when used in conjunction with Repeater fields, don't persist. I realise that Repeater fields are still in beta, but don't see anything in the documentation at https://nova.laravel.com/docs/resources/repeater-fields.html covering that.
My table structure is as follows ...
My classes are as follows ...
app/Models/Product.php:
app/Models/ProductImage.php:
app/Nova/Product.php:
app/Nova/Repeater/ProductImage.php:
Detailed steps to reproduce the issue on a fresh Nova installation:
Add a product image (repeatable) ...
Select image (file) ...
Update product (model) ...
Confirm
product_images
.image
column contains correct value ...Update product (model) again ...
Notice the
product_images
.image
column no longer has a value ...In closing
I suspect that the
image
column's value is empty after subsequent saves because those rows are deleted and recreated (as per https://nova.laravel.com/docs/resources/repeater-fields.html#upserting-repeatables-using-unique-fields), for some reason the original value isn't included in the XHR payload, and it looks like that image attribute will therefore only be "filled" if a new file is uploaded.I have been able to get that
image
column's values to persist by specifying a unique field so that upserts are run instead (ie.->uniqueField('uuid')
), but then the reordering of images (repeatables) no longer work.