theTechnician's avatar

How to display an array of JSON objects

Hello all.

I'm a little stuck trying to display an array of JSON objects (other solutions welcome).

Currently the data looks like: [{"description":"Product Test","sku":"TEST01"},{"description":"Product Test","sku":"TEST01"}].

I thought a Repeater field would work, then use Text fields for the JSON object keys, but I get an error of "Undefined array key 'type'". I've tried casting the column as an array, but still get the same error. Also tried the KeyValue field, but I assume that to be used with a single JSON object which then returns the keys and values?

The data doesn't have to be in this format. I've made a command to pick this data out from a larger data set, so I can change how it's stored if needed.

0 likes
6 replies
marinm's avatar

I have the same problem, it should work according to the docs. Did you find a solution?

jameswagoner's avatar

Docs are a little confusing and you can easily miss it right at the top of the page.

The Repeater field allows you to create and edit repeatable, structured data...

Repeater fields are only shown on forms. Meaning creating and editing a resource.

I am with you guys. I have a json column that is an array of images and a type. I just wanna display out of the box. However, I think we are left to create our own custom field or panel.

jameswagoner's avatar

I ended up going simple with a loop and adding to the array with a spread operator

$attachments = [];
foreach ($this->resource->media as $media) {
    $attachments[] = Image::make('Media', 'local')
        ->preview(fn () => $media['url'])
        ->onlyOnDetail(); 
}

return [
    // other fields

    ...$attachments,
];

Even then, the Image field wants to use the Storage adapter. I have a full url path already so I had to use the local disk and use the preview() method to pass the url.

khbtech's avatar

I just ran into this issue and tripped upon the answer. I was only able to figure it out by using the Repeater on a new record, then inspecting the entry in the database.

To begin, you want to create a Repeatable such as:

php artisan nova:repeatable ValidationRule

Then you build your Repeatable as shown in the docs. In my case it looked like this:

    public function fields(NovaRequest $request)
    {
        return [
            Text::make('Field')->rules('required'),
            Text::make('Rule')
        ];
    }

Then, you add that to your resource's list of fields. Something like this, where ruleset is the name of the JSON field on my model:

Repeater::make('Ruleset')
    ->repeatables([
        ValidationRule::make()
    ])->asJson(),

Now, here's the kicker. If you already have data in the database, you'll need to reformat your JSON field so that each entry is an object with two keys:

  • type which is the kebab form of your Repeatable object's name (mine is not in a subfolder of the Repeater folder, so if yours is, I don't know if that will affect the name).
  • fields which is an object of all your items, keyed by your Repeatable field names

In my case, it looked something like this in the DB:

[{"type":"validation-rule","fields":{"field":"date_of_entry","rule":"date"}},{"type":"validation-rule","fields":{"field":"parent_name","rule":"required, alpha"}}]

Once I manually edited all the model records that already existed, the repeater worked as intended.

Hopefully that helps someone out.

Please or to participate in this conversation.