Strapi V4 populate Media and Dynamiczones from Components

Ok so I figured it out. First, make sure to update your strapi to the latest version (4.0.2) since my repo is on that version.

Introduction

I will explain and provide you with an example of how you can deeply populate nested components and dynamiz zones in the v4 of Strapi.

Structure

  • I have created a single type content named layout with 2 dynamic zones and some nested fields and components to them
    • Header (Dynamic Zone)
      • Logo (Component)
    • Sidebar (Dynamic Zone)
      • Avatar (Component)
        • name
        • img
      • Menu (Component)
        • heading
        • links (Repeatable Component)
          • title
          • icon

Then I enabled the find controller for this content type from the setting.

Normally the API would return this data for this model by default:

{
    "data": {
        "id": 1,
        "attributes": {
            "createdAt": "2021-12-25T07:35:17.286Z",
            "updatedAt": "2021-12-25T08:03:48.671Z",
            "publishedAt": "2021-12-25T07:35:18.676Z"
        }
    },
    "meta": {}
}

But we can overwrite/extend the core find controller (you can also create a new route/controller) instead.

In order to do this, modify the code in the following file:

src\api\layout\controllers\layout.js
'use strict';

/**
 *  layout controller
 */

const { createCoreController } = require('@strapi/strapi').factories;

module.exports = createCoreController('api::layout.layout', ({ strapi }) => ({
    async find(ctx) {
        const { query } = ctx;

        const entity = await strapi.entityService.findMany('api::layout.layout', {
            ...query,
            populate: {
                header: {
                    populate: {
                        img: true
                    }
                },
                sidebar: {
                    populate: {
                        img: true, links: {
                            populate: {
                                icon: true
                            }
                        }
                    }
                },
            },
        });
        const sanitizedEntity = await this.sanitizeOutput(entity, ctx);

        return this.transformResponse(sanitizedEntity);

    }
}));

Pay attention to the api::layout.layout which is the UID for your specific content type and field.

Now that looks like the data we are looking for:

Now of course, you should review the core controllers and your business logic to make sure you are handling permissions and parameter passing correctly and necessarily… but this should get you started!

Here is a repo: https://github.com/nextrapi/Strapi_v4_Deep_Populate

All the best!

8 Likes