Skip to main content

Deep dive: A block's lifecycle

A block usually exists in all three microservices (API, Admin, and Site) and the database. When transitioning between these microservices, the block is represented in different states, for instance, block input or block data. In this section, we show the different states a block can have.

The block in the database

Blocks are stored as JSON columns in the database. Blocks at the root level of the entity are called root blocks. To add a block to an entity, the custom type RootBlockType needs to be used:

any.entity.ts
@Entity()
@RootBlockEntity()
class AnyEntity {
/* Other fields */

@RootBlock(DamImageBlock)
@Property({ customType: new RootBlockType(DamImageBlock) })
image: BlockDataInterface;
}

When a block is converted to the database value, it is split into two fields, data and index.

  • data contains the actual data of the block.
  • index contains the index data of the block. The index data is a flat representation of all child blocks in a root block, including some meta information such as the block's path and visibility. The index can be used for different use cases, for instance, linking to a block's dependencies.

When a block is converted to the JavaScript value, the index data is ignored, and only the block data is used.

Example of an image block in the database
{
"data": {
"attachedBlocks": [
{
"type": "pixelImage",
"props": { "damFileId": "efbd89db-9b39-49fb-a0d7-6491ca228dec" }
}
],
"activeType": "pixelImage"
},
"index": [
{ "blockname": "DamImage", "jsonPath": "root", "visible": true },
{
"blockname": "PixelImage",
"jsonPath": "root.attachedBlocks.0.props",
"visible": true,
"dependencies": [
{ "targetEntityName": "DamFile", "id": "efbd89db-9b39-49fb-a0d7-6491ca228dec" }
]
}
]
}

The block in the API

In the API, the block can have one of the four states: data, plain, input, or save.

  • Block data is the data of a block instance in the API.
  • Block plain is a block's data that is sent to the clients. It consists of the block data and optional additional fields. For instance, it may add a loaded DAM image to the block data, whereas the data only contains the image ID.
  • Block input is the data that's coming from the Admin. It is used to create the block data.
  • Block save is the block's data that is to be saved in the database.
tip

You can think of the block data as the GraphQL object type and the block input as the GraphQL input type.

Transitioning between states

Different block states in the API

The following methods are used to transition between the different block states:

  • The BlockInput#transformToBlockData method is used to transition from input to data. You can usually use the inputToData helper for this.

    class HeadlineBlockInput extends BlockInput {
    /* ... */

    transformToBlockData(): HeadlineBlockData {
    return inputToData(HeadlineBlockData, this);
    }
    }
  • The transformToSave function is used to transition from data to save. You likely won't call this function directly, since RootBlockType takes care of this.

    const headlineBlockData = /* Block instance in the API */;
    const headlineBlockSave = transformToSave(headlineBlockData);
  • The Block#blockDataFactory method is used to transition from save to data. RootBlockType also takes care of this.

    const headlineBlockSave = /* Loaded from the database */;
    const headlineBlockData = HeadlineBlock.blockDataFactory(headlineBlockSave);
  • The transformToPlain function is used to transition from data to plain. You will likely use the BlocksTransformerService for this.

    class PagesResolver {
    @ResolveField(() => RootBlockDataScalar(HeadlineBlock))
    async headline(@Parent() page: Page) {
    return this.blocksTransformer.transformToPlain(page.headline);
    }
    }

The block in the Admin

In the Admin, the block can have one of the four states: input, state, output, or preview state.

  • Block input is the data (transformed to plain) of a block coming from the API.
  • Block state is the data of a block while editing.
  • Block output is the data sent to the API when saving a block.
  • Block preview state is the data sent to the preview while editing.
tip

The API's output (= data) is the Admin's input, and the Admin's output is the API's input.

Transitioning between states

Different block states in the Admin

The following methods are used to transition between the different block states:

  • The BlockInterface#input2State method is used to transition from input to state.

    const headlineBlockInput = /* Block data from the API */;
    const headlineBlockState = HeadlineBlock.input2State(headlineBlockInput);
  • The BlockInterface#state2Output method is used to transition from state to output.

    const headlineBlockState = /* Block state in the Admin */;
    const headlineBlockOutput = HeadlineBlock.state2Output(headlineBlockState);
  • The BlockInterface#output2State method is used to transition from output to state.

    const headlineBlockOutput = /* Block output from the Admin */;
    const headlineBlockState = await HeadlineBlock.output2State(headlineBlockOutput);
  • The BlockInterface#createPreviewState method is used to create a preview state. The preview state, together with the preview context, displays the block currently being edited in the block preview.

    const previewContext = /* Context for the preview, e.g., showVisibleOnly */

    const headlineBlockState = /* Block state in the Admin */;
    const headlineBlockPreviewState = HeadlineBlock.createPreviewState(headlineBlockState, previewContext);

The block in the site

In the site, the block can only have one state: plain. It is the transformed block data coming from the API.

Full block lifecycle

Now that we've seen the different block states in all three microservices let's examine the big picture. You can see a block's full lifecycle across the microservices in the following figure:

Full block lifecycle