diff --git a/16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md b/16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md index d691f680500..633dbf3dc15 100644 --- a/16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md +++ b/16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md @@ -458,20 +458,20 @@ Building Custom Views for Block representations in Backoffice is based on the sa In this example, we will be creating content programmatically for a "spot" Blocks in a Block Grid. -1. On a Document Type add a property called **blockGrid**. -2. Then add as editor **Block Grid**. -3. In the Block Grid add a new block and click to **Create new Element Type** -4. Name this element type **spotElement** with the following properties: +1. Create an element type to represent block content called **Spot Element** with the following properties: * A property called **title** with the editor of **Textstring** * A property called **text** with the editor of **Textstring** -5. Then on the **Settings model** click to add a new Setting. -6. Then click to **Create new Element Type**. -7. Name this element type **spotSettings** with the following properties: +2. Create an element type to represent block content called **Spot Settings** with the following properties: * A property called **featured** with the editor of **True/false**. +3. Add a property called **blockGrid** in a Document Type. +4. Select **Block Grid** as the property editor. +5. Click **Add** in the **Blocks** Settings and select **Spot Element**. +6. Select **Spot Settings** in the **Settings model** field. + ![Block Grid - Block Configuration](../../../images/BlockEditorConfigurationProgramatically.png) The raw input data for the spots looks like this: @@ -488,44 +488,118 @@ The resulting JSON object stored for the Block Grid will look like this: ```json { - "layout": { - "Umbraco.BlockGrid": [{ - "contentUdi": "umb://element/bb23fe28160941efa506da7aa314172d", - "settingsUdi": "umb://element/9b832ee528464456a8e9a658b47a9801", - "areas": [], - "columnSpan": 12, - "rowSpan": 1 - }, { - "contentUdi": "umb://element/a11e06ca155d40b78189be0bdaf11c6d", - "settingsUdi": "umb://element/d182a0d807fc4518b741b77c18aa73a1", - "areas": [], - "columnSpan": 6, - "rowSpan": 2 + "contentData":[ + { + "contentTypeKey":"fd01539a-5bcf-48f7-aee5-8ad925c75902", + "udi":null, + "key":"019f2a7a-35b4-45b3-b867-910b3f340f25", + "values":[ + { + "editorAlias":"Umbraco.TextBox", + "culture":null, + "segment":null, + "alias":"title", + "value":"Item one" + }, + { + "editorAlias":"Umbraco.TextBox", + "culture":null, + "segment":null, + "alias":"text", + "value":"This is item one" } - ] - }, - "contentData": [{ - "contentTypeKey": "0e9f8609-1904-4fd1-9801-ad1880825ff3", - "udi": "umb://element/bb23fe28160941efa506da7aa314172d", - "title": "Item one", - "text": "This is item one" - }, { - "contentTypeKey": "0e9f8609-1904-4fd1-9801-ad1880825ff3", - "udi": "umb://element/a11e06ca155d40b78189be0bdaf11c6d", - "title": "Item two", - "text": "This is item two" - } - ], - "settingsData": [{ - "contentTypeKey": "22be457c-8249-42b8-8685-d33262f7ce2a", - "udi": "umb://element/9b832ee528464456a8e9a658b47a9801", - "featured": "0" - }, { - "contentTypeKey": "22be457c-8249-42b8-8685-d33262f7ce2a", - "udi": "umb://element/d182a0d807fc4518b741b77c18aa73a1", - "featured": "1" - } - ] + ] + }, + { + "contentTypeKey":"fd01539a-5bcf-48f7-aee5-8ad925c75902", + "udi":null, + "key":"063f8062-8610-441a-97f1-ea6d73fe2678", + "values":[ + { + "editorAlias":"Umbraco.TextBox", + "culture":null, + "segment":null, + "alias":"title", + "value":"Item two" + }, + { + "editorAlias":"Umbraco.TextBox", + "culture":null, + "segment":null, + "alias":"text", + "value":"This is item two" + } + ] + } + ], + "settingsData":[ + { + "contentTypeKey":"03c43074-a4ba-4bd2-92b1-c3a35a0eed4d", + "udi":null, + "key":"5b2d74bc-3e85-4aa3-b684-4b1f11522d7c", + "values":[ + { + "editorAlias":"Umbraco.TrueFalse", + "culture":null, + "segment":null, + "alias":"featured", + "value":0 + } + ] + }, + { + "contentTypeKey":"03c43074-a4ba-4bd2-92b1-c3a35a0eed4d", + "udi":null, + "key":"1c6599fc-6558-4a0b-9da8-4f002925f59f", + "values":[ + { + "editorAlias":"Umbraco.TrueFalse", + "culture":null, + "segment":null, + "alias":"featured", + "value":1 + } + ] + } + ], + "expose":[ + { + "contentKey":"019f2a7a-35b4-45b3-b867-910b3f340f25", + "culture":null, + "segment":null + }, + { + "contentKey":"063f8062-8610-441a-97f1-ea6d73fe2678", + "culture":null, + "segment":null + } + ], + "Layout":{ + "Umbraco.BlockGrid":[ + { + "columnSpan":12, + "rowSpan":1, + "areas":[ + + ], + "contentUdi":null, + "settingsUdi":null, + "contentKey":"019f2a7a-35b4-45b3-b867-910b3f340f25", + "settingsKey":"5b2d74bc-3e85-4aa3-b684-4b1f11522d7c" + }, + { + "columnSpan":12, + "rowSpan":1, + "areas":[ + + ], + "contentUdi":null, + "settingsUdi":null, + "contentKey":"063f8062-8610-441a-97f1-ea6d73fe2678", + "settingsKey":"1c6599fc-6558-4a0b-9da8-4f002925f59f" + } + ] + } } ``` @@ -537,32 +611,84 @@ For each item in the raw data, we need to create: All `contentData` and `layoutData` entries need their own unique `Udi` as well as the ID (key) of their corresponding Element Types. In this sample, we only have one Element Type for content (`spotElement`) and one for settings (`spotSettings`). In a real life scenario, there could be any number of Element Type combinations. -8. First and foremost, we need models to transform the raw data into Block Grid compatible JSON. Create a class called **Model.cs** containing the following: +7. Create a class called **Model.cs** containing the following to transform the raw data into Block Grid-compatible JSON: {% code title="Models.cs" lineNumbers="true" %} ```csharp -using Umbraco.Cms.Core; using System.Text.Json.Serialization; + namespace My.Site.Models; // this is the "root" of the block grid data public class BlockGridData { - public BlockGridData(BlockGridLayout layout, BlockGridElementData[] contentData, BlockGridElementData[] settingsData) + public BlockGridData(BlockGridElementData[] contentData, BlockGridElementData[] settingsData, BlockGridExposeData[] expose, BlockGridLayout layout) { - Layout = layout; ContentData = contentData; SettingsData = settingsData; + Expose = expose; + Layout = layout; } - [JsonPropertyName("layout")] - public BlockGridLayout Layout { get; } - [JsonPropertyName("contentData")] public BlockGridElementData[] ContentData { get; } [JsonPropertyName("settingsData")] public BlockGridElementData[] SettingsData { get; } + + [JsonPropertyName("expose")] + public BlockGridExposeData[] Expose { get; } + + [JsonPropertyName("Layout")] + public BlockGridLayout Layout { get; } +} + +// this represents an item in the block grid content or settings data collection +public class BlockGridElementData +{ + public BlockGridElementData(Guid contentTypeKey, Guid key, BlockGridValueData[] values) + { + ContentTypeKey = contentTypeKey; + Key = key; + Values = values; + } + + [JsonPropertyName("contentTypeKey")] + public Guid ContentTypeKey { get; } + + [JsonPropertyName("key")] + public Guid Key { get; } + + [JsonPropertyName("values")] + public BlockGridValueData[] Values { get; } +} + +public class BlockGridValueData +{ + public BlockGridValueData(string alias, string editorAlias, object? value) + { + Alias = alias; + EditorAlias = editorAlias; + Value = value; + } + + [JsonPropertyName("alias")] + public string Alias { get; } + + [JsonPropertyName("editorAlias")] + public string EditorAlias { get; } + + [JsonPropertyName("value")] + public object? Value { get; } +} + +// this represents an item in the block grid expose data collection +public class BlockGridExposeData +{ + public BlockGridExposeData(Guid contentKey) => ContentKey = contentKey; + + [JsonPropertyName("contentKey")] + public Guid ContentKey { get; } } // this is a wrapper for the block grid layout, purely required for correct serialization @@ -577,60 +703,39 @@ public class BlockGridLayout // this represents an item in the block grid layout collection public class BlockGridLayoutItem { - public BlockGridLayoutItem(Udi contentUdi, Udi settingsUdi, int columnSpan, int rowSpan) + public BlockGridLayoutItem(int columnSpan, int rowSpan, Guid contentKey, Guid settingsKey) { - ContentUdi = contentUdi; - SettingsUdi = settingsUdi; ColumnSpan = columnSpan; RowSpan = rowSpan; + ContentKey = contentKey; + SettingsKey = settingsKey; } - [JsonPropertyName("contentUdi")] - public Udi ContentUdi { get; } - - [JsonPropertyName("settingsUdi")] - public Udi SettingsUdi { get; } - - [JsonPropertyName("areas")] - // areas are omitted from this sample for abbreviation - public object[] Areas { get; } = { }; - [JsonPropertyName("columnSpan")] public int ColumnSpan { get; } [JsonPropertyName("rowSpan")] public int RowSpan { get; } -} + [JsonPropertyName("contentKey")] + public Guid ContentKey { get; } -// this represents an item in the block grid content or settings data collection -public class BlockGridElementData -{ - public BlockGridElementData(Guid contentTypeKey, Udi udi) - { - ContentTypeKey = contentTypeKey; - Udi = udi; - } + [JsonPropertyName("settingsKey")] + public Guid SettingsKey { get; } - [JsonPropertyName("contentTypeKey")] - public Guid ContentTypeKey { get; } - - [JsonPropertyName("udi")] - public Udi Udi { get; } - - [JsonExtensionData] - public Dictionary? Data { get; set;} + [JsonPropertyName("areas")] + // areas are omitted from this sample for abbreviation + public object[] Areas { get; } = []; } ``` {% endcode %} -9. By injecting [ContentService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html) and [ContentTypeService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentTypeService.html) into an API controller, we can transform the raw data into Block Grid JSON. It can then be saved to the target content item. Create a class called **BlockGridTestController.cs** containing the following: +8. Create a class called **BlockGridTestController.cs**. By injecting `IContentService` and `IContentTypeService` into an API controller, the raw data can be transformed into Block Grid JSON. It can then be saved to the target content item. {% code title="BlockGridTestController.cs" lineNumbers="true" %} ```csharp using Microsoft.AspNetCore.Mvc; using My.Site.Models; -using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; @@ -657,7 +762,7 @@ public class BlockGridTestController : Controller public ActionResult Create() { // get the item content to modify - IContent? content = _contentService.GetById(Guid.Parse("efba7b97-91b6-4ddf-b2cc-eef89ff48c3b")); + IContent? content = _contentService.GetById(Guid.Parse("7ed0bd1f-2a52-4b45-9811-2560b907fe48")); if (content == null) { return NotFound("Could not find the content item to modify"); @@ -679,43 +784,44 @@ public class BlockGridTestController : Controller }; // build the individual parts of the block grid data from the raw data + var contentData = new List(); + var settingsData = new List(); + var exposeData = new List(); var layoutItems = new List(); - var spotContentData = new List(); - var spotSettingsData = new List(); foreach (var data in rawData) { - // generate new UDIs for block content and settings - var contentUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid()); - var settingsUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid()); - - // create a new layout item - layoutItems.Add(new BlockGridLayoutItem(contentUdi, settingsUdi, data.ColumnSpan, data.RowSpan)); + // generate new keys for block content and settings + var contentKey = Guid.NewGuid(); + var settingsKey = Guid.NewGuid(); // create new content data - spotContentData.Add(new BlockGridElementData(spotContentType.Key, contentUdi) + var contentValues = new BlockGridValueData[] { - Data = new Dictionary - { - { "title", data.Title }, - { "text", data.Text }, - } - }); + new("title", "Umbraco.TextBox", data.Title), + new("text", "Umbraco.TextBox", data.Text), + }; + contentData.Add(new BlockGridElementData(spotContentType.Key, contentKey, contentValues)); // create new settings data - spotSettingsData.Add(new BlockGridElementData(spotSettingsType.Key, settingsUdi) + var settingValues = new BlockGridValueData[] { - Data = new Dictionary - { - { "featured", data.Featured ? "1" : "0" }, - } - }); + new("featured", "Umbraco.TrueFalse", data.Featured ? "1" : "0"), + }; + settingsData.Add(new BlockGridElementData(spotSettingsType.Key, settingsKey, settingValues)); + + // create a new expose item + exposeData.Add(new BlockGridExposeData(contentKey)); + + // create a new layout item + layoutItems.Add(new BlockGridLayoutItem(data.ColumnSpan, data.RowSpan, contentKey, settingsKey)); } // construct the block grid data from layout, content and settings var blockGridData = new BlockGridData( - new BlockGridLayout(layoutItems.ToArray()), - spotContentData.ToArray(), - spotSettingsData.ToArray()); + [.. contentData], + [.. settingsData], + [.. exposeData], + new BlockGridLayout([.. layoutItems])); // serialize the block grid data as JSON and save it to the "blockGrid" property on the content item var propertyValue = _serializer.Serialize(blockGridData); @@ -728,10 +834,8 @@ public class BlockGridTestController : Controller ``` {% endcode %} -For the above code `IContent? content = _contentService.GetById(1203);` change the id with your content node that is using the Block Grid. +For the above code `IContent? content = _contentService.GetById(Guid.Parse("efba7b97-91b6-4ddf-b2cc-eef89ff48c3b"));` change the id with your content node that is using the Block Grid. -10. In order to test this implementation, run the project and add `/umbraco/api/blockgridtest/create` after your domain name. If the result shows as **Saved** then check your content node and you will see the 2 spotElement contents. +10. To test this implementation, run the project and send a `POST` request to `/umbraco/api/blockgridtest/create` after your domain name. If the result shows as **Saved**, then check your content node, and you will see the 2 spotElement contents. ![Block Grid - Result](../../../images/BlockEditorContentCreated.png) - -_This can also be tested via Postman as well if preffered._ diff --git a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md index ac99f5c73e4..dde41c1537f 100644 --- a/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md +++ b/17/umbraco-cms/fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-grid-editor.md @@ -16,7 +16,7 @@ This article is a work in progress and may undergo further revisions, updates, o When testing out the property editor, you can use a set of predefined Blocks. The option will only be possible when there are no other Data Types using the Block Grid property editor. -
+
* Create a new **Data Type**. * Select the **Block Grid** as the **Property editor**. @@ -37,7 +37,7 @@ To set up the Block Grid property editor, follow these steps: You will see the configuration options for a Block Grid property editor as shown below: -![Block Grid - Data Type Configuration](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png) +![Block Grid - Data Type Configuration](../../built-in-property-editors/block-editor/images/BlockGridEditor_Configuration.png) The Data Type editor allows you to configure the following properties: @@ -55,7 +55,7 @@ Block Types are based on [**Element Types**](../../../../data/defining-content/d Once you have added an Element Type as a Block Type on your Block Grid Data Type you have the option to configure it. -![Block Grid - Data Type Block Configuration](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png) +![Block Grid - Data Type Block Configuration](../../built-in-property-editors/block-editor/images/BlockGridEditor_DataType_Blocks.png) ### Groups @@ -126,11 +126,11 @@ To scale an Area, click and drag the scale-button in the bottom-right corner of * **Grid Columns for Areas** - Overwrites the amount of columns used for the Area grid. * **Areas** - Determines whether the Block can be created inside Areas of other Blocks. -![Block Grid - Areas](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png) +![Block Grid - Areas](../../built-in-property-editors/block-editor/images/BlockGridEditor_Areas.png) ### Area configuration -![Block Grid - Area Configuration](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png) +![Block Grid - Area Configuration](../../built-in-property-editors/block-editor/images/BlockGridEditor_AreasConfiguration.png) * **Alias** - The alias is used to identify this Area. It is being printed by `GetBlockGridHTML()` and used as name for the Area slot in Custom Views. The alias is also available for CSS Selectors to target the HTML-Element representing an Area. * **Create Button Label** - Overwrites the Create Button Label of the Area. @@ -157,25 +157,25 @@ Notice that any styling of a Block is scoped. This means that the default backof When viewing a **Block Grid** property editor in the **Content** section for the first time, you will be presented with the option to **Add content**. -![Block Grid - Add Content](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png) +![Block Grid - Add Content](../../built-in-property-editors/block-editor/images/BlockGridEditor_AddContent.png) Clicking the **Add content** button opens up the **Block Catalogue**. -![Block Grid - Setup](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png) +![Block Grid - Setup](../../built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker.png) The Block Catalogue looks different depending on the amount of available Blocks and their catalogue appearance. -![Block Grid - example setup](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png) +![Block Grid - example setup](../../built-in-property-editors/block-editor/images/BlockGridEditor_BlockPicker_exsetup.png) Click the Block Type you wish to create and a new Block will appear in the layout. More Blocks can be added to the layout by clicking the Add content button. Alternatively, use the Add content button that appears on hover to add new Blocks between, besides, or above the existing Blocks. -![Block Grid - Add Content Inline](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png) +![Block Grid - Add Content Inline](../../built-in-property-editors/block-editor/images/BlockGridEditor_AddContentInline.png) To delete a Block, click the trash icon which appears on the mouse hover. -![Block Grid - Delete Content](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png) +![Block Grid - Delete Content](../../built-in-property-editors/block-editor/images/BlockGridEditor_DeleteContent.png) ## Sorting Blocks @@ -183,7 +183,7 @@ Blocks can be rearranged using the click and drag feature. Move them up or down Moving a Block from one Area to another is done in the same way. If a Block is not allowed in the given position, the area will display a red color and not allow the new position. -![Block Grid - Sorting Blocks](../../../../../../../16/umbraco-cms/fundamentals/backoffice/property-editors/built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif) +![Block Grid - Sorting Blocks](../../built-in-property-editors/block-editor/images/Sorting_BlockGrid_Blocks.gif) ## Scaling Blocks @@ -191,7 +191,7 @@ If a Block has multiple size options it can be scaled via the UI. This appears i The Block is resized using a click-and-drag feature. Moving the mouse will change the size to the size options closest to the mouse pointer. -

Scale blocks in the grid by dragging from the bottom-right corner.

+

Scale blocks in the grid by dragging from the bottom-right corner.

## Rendering Block Grid Content @@ -458,20 +458,20 @@ Building Custom Views for Block representations in Backoffice is based on the sa In this example, we will be creating content programmatically for a "spot" Blocks in a Block Grid. -1. On a Document Type add a property called **blockGrid**. -2. Then add as editor **Block Grid**. -3. In the Block Grid add a new block and click to **Create new Element Type** -4. Name this element type **spotElement** with the following properties: +1. Create an element type to represent block content called **Spot Element** with the following properties: * A property called **title** with the editor of **Textstring** * A property called **text** with the editor of **Textstring** -5. Then on the **Settings model** click to add a new Setting. -6. Then click to **Create new Element Type**. -7. Name this element type **spotSettings** with the following properties: +2. Create an element type to represent block content called **Spot Settings** with the following properties: * A property called **featured** with the editor of **True/false**. +3. Add a property called **blockGrid** in a Document Type. +4. Select **Block Grid** as the property editor. +5. Click **Add** in the **Blocks** Settings and select **Spot Element**. +6. Select **Spot Settings** in the **Settings model** field. + ![Block Grid - Block Configuration](../../../images/BlockEditorConfigurationProgramatically.png) The raw input data for the spots looks like this: @@ -488,44 +488,118 @@ The resulting JSON object stored for the Block Grid will look like this: ```json { - "layout": { - "Umbraco.BlockGrid": [{ - "contentUdi": "umb://element/bb23fe28160941efa506da7aa314172d", - "settingsUdi": "umb://element/9b832ee528464456a8e9a658b47a9801", - "areas": [], - "columnSpan": 12, - "rowSpan": 1 - }, { - "contentUdi": "umb://element/a11e06ca155d40b78189be0bdaf11c6d", - "settingsUdi": "umb://element/d182a0d807fc4518b741b77c18aa73a1", - "areas": [], - "columnSpan": 6, - "rowSpan": 2 + "contentData":[ + { + "contentTypeKey":"fd01539a-5bcf-48f7-aee5-8ad925c75902", + "udi":null, + "key":"019f2a7a-35b4-45b3-b867-910b3f340f25", + "values":[ + { + "editorAlias":"Umbraco.TextBox", + "culture":null, + "segment":null, + "alias":"title", + "value":"Item one" + }, + { + "editorAlias":"Umbraco.TextBox", + "culture":null, + "segment":null, + "alias":"text", + "value":"This is item one" } - ] - }, - "contentData": [{ - "contentTypeKey": "0e9f8609-1904-4fd1-9801-ad1880825ff3", - "udi": "umb://element/bb23fe28160941efa506da7aa314172d", - "title": "Item one", - "text": "This is item one" - }, { - "contentTypeKey": "0e9f8609-1904-4fd1-9801-ad1880825ff3", - "udi": "umb://element/a11e06ca155d40b78189be0bdaf11c6d", - "title": "Item two", - "text": "This is item two" - } - ], - "settingsData": [{ - "contentTypeKey": "22be457c-8249-42b8-8685-d33262f7ce2a", - "udi": "umb://element/9b832ee528464456a8e9a658b47a9801", - "featured": "0" - }, { - "contentTypeKey": "22be457c-8249-42b8-8685-d33262f7ce2a", - "udi": "umb://element/d182a0d807fc4518b741b77c18aa73a1", - "featured": "1" - } - ] + ] + }, + { + "contentTypeKey":"fd01539a-5bcf-48f7-aee5-8ad925c75902", + "udi":null, + "key":"063f8062-8610-441a-97f1-ea6d73fe2678", + "values":[ + { + "editorAlias":"Umbraco.TextBox", + "culture":null, + "segment":null, + "alias":"title", + "value":"Item two" + }, + { + "editorAlias":"Umbraco.TextBox", + "culture":null, + "segment":null, + "alias":"text", + "value":"This is item two" + } + ] + } + ], + "settingsData":[ + { + "contentTypeKey":"03c43074-a4ba-4bd2-92b1-c3a35a0eed4d", + "udi":null, + "key":"5b2d74bc-3e85-4aa3-b684-4b1f11522d7c", + "values":[ + { + "editorAlias":"Umbraco.TrueFalse", + "culture":null, + "segment":null, + "alias":"featured", + "value":0 + } + ] + }, + { + "contentTypeKey":"03c43074-a4ba-4bd2-92b1-c3a35a0eed4d", + "udi":null, + "key":"1c6599fc-6558-4a0b-9da8-4f002925f59f", + "values":[ + { + "editorAlias":"Umbraco.TrueFalse", + "culture":null, + "segment":null, + "alias":"featured", + "value":1 + } + ] + } + ], + "expose":[ + { + "contentKey":"019f2a7a-35b4-45b3-b867-910b3f340f25", + "culture":null, + "segment":null + }, + { + "contentKey":"063f8062-8610-441a-97f1-ea6d73fe2678", + "culture":null, + "segment":null + } + ], + "Layout":{ + "Umbraco.BlockGrid":[ + { + "columnSpan":12, + "rowSpan":1, + "areas":[ + + ], + "contentUdi":null, + "settingsUdi":null, + "contentKey":"019f2a7a-35b4-45b3-b867-910b3f340f25", + "settingsKey":"5b2d74bc-3e85-4aa3-b684-4b1f11522d7c" + }, + { + "columnSpan":12, + "rowSpan":1, + "areas":[ + + ], + "contentUdi":null, + "settingsUdi":null, + "contentKey":"063f8062-8610-441a-97f1-ea6d73fe2678", + "settingsKey":"1c6599fc-6558-4a0b-9da8-4f002925f59f" + } + ] + } } ``` @@ -537,32 +611,84 @@ For each item in the raw data, we need to create: All `contentData` and `layoutData` entries need their own unique `Udi` as well as the ID (key) of their corresponding Element Types. In this sample, we only have one Element Type for content (`spotElement`) and one for settings (`spotSettings`). In a real life scenario, there could be any number of Element Type combinations. -8. First and foremost, we need models to transform the raw data into Block Grid compatible JSON. Create a class called **Model.cs** containing the following: +7. Create a class called **Model.cs** containing the following to transform the raw data into Block Grid-compatible JSON: {% code title="Models.cs" lineNumbers="true" %} ```csharp -using Umbraco.Cms.Core; using System.Text.Json.Serialization; + namespace My.Site.Models; // this is the "root" of the block grid data public class BlockGridData { - public BlockGridData(BlockGridLayout layout, BlockGridElementData[] contentData, BlockGridElementData[] settingsData) + public BlockGridData(BlockGridElementData[] contentData, BlockGridElementData[] settingsData, BlockGridExposeData[] expose, BlockGridLayout layout) { - Layout = layout; ContentData = contentData; SettingsData = settingsData; + Expose = expose; + Layout = layout; } - [JsonPropertyName("layout")] - public BlockGridLayout Layout { get; } - [JsonPropertyName("contentData")] public BlockGridElementData[] ContentData { get; } [JsonPropertyName("settingsData")] public BlockGridElementData[] SettingsData { get; } + + [JsonPropertyName("expose")] + public BlockGridExposeData[] Expose { get; } + + [JsonPropertyName("Layout")] + public BlockGridLayout Layout { get; } +} + +// this represents an item in the block grid content or settings data collection +public class BlockGridElementData +{ + public BlockGridElementData(Guid contentTypeKey, Guid key, BlockGridValueData[] values) + { + ContentTypeKey = contentTypeKey; + Key = key; + Values = values; + } + + [JsonPropertyName("contentTypeKey")] + public Guid ContentTypeKey { get; } + + [JsonPropertyName("key")] + public Guid Key { get; } + + [JsonPropertyName("values")] + public BlockGridValueData[] Values { get; } +} + +public class BlockGridValueData +{ + public BlockGridValueData(string alias, string editorAlias, object? value) + { + Alias = alias; + EditorAlias = editorAlias; + Value = value; + } + + [JsonPropertyName("alias")] + public string Alias { get; } + + [JsonPropertyName("editorAlias")] + public string EditorAlias { get; } + + [JsonPropertyName("value")] + public object? Value { get; } +} + +// this represents an item in the block grid expose data collection +public class BlockGridExposeData +{ + public BlockGridExposeData(Guid contentKey) => ContentKey = contentKey; + + [JsonPropertyName("contentKey")] + public Guid ContentKey { get; } } // this is a wrapper for the block grid layout, purely required for correct serialization @@ -577,60 +703,39 @@ public class BlockGridLayout // this represents an item in the block grid layout collection public class BlockGridLayoutItem { - public BlockGridLayoutItem(Udi contentUdi, Udi settingsUdi, int columnSpan, int rowSpan) + public BlockGridLayoutItem(int columnSpan, int rowSpan, Guid contentKey, Guid settingsKey) { - ContentUdi = contentUdi; - SettingsUdi = settingsUdi; ColumnSpan = columnSpan; RowSpan = rowSpan; + ContentKey = contentKey; + SettingsKey = settingsKey; } - [JsonPropertyName("contentUdi")] - public Udi ContentUdi { get; } - - [JsonPropertyName("settingsUdi")] - public Udi SettingsUdi { get; } - - [JsonPropertyName("areas")] - // areas are omitted from this sample for abbreviation - public object[] Areas { get; } = { }; - [JsonPropertyName("columnSpan")] public int ColumnSpan { get; } [JsonPropertyName("rowSpan")] public int RowSpan { get; } -} + [JsonPropertyName("contentKey")] + public Guid ContentKey { get; } -// this represents an item in the block grid content or settings data collection -public class BlockGridElementData -{ - public BlockGridElementData(Guid contentTypeKey, Udi udi) - { - ContentTypeKey = contentTypeKey; - Udi = udi; - } + [JsonPropertyName("settingsKey")] + public Guid SettingsKey { get; } - [JsonPropertyName("contentTypeKey")] - public Guid ContentTypeKey { get; } - - [JsonPropertyName("udi")] - public Udi Udi { get; } - - [JsonExtensionData] - public Dictionary? Data { get; set;} + [JsonPropertyName("areas")] + // areas are omitted from this sample for abbreviation + public object[] Areas { get; } = []; } ``` {% endcode %} -9. By injecting [ContentService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentService.html) and [ContentTypeService](https://apidocs.umbraco.com/v15/csharp/api/Umbraco.Cms.Core.Services.ContentTypeService.html) into an API controller, we can transform the raw data into Block Grid JSON. It can then be saved to the target content item. Create a class called **BlockGridTestController.cs** containing the following: +8. Create a class called **BlockGridTestController.cs**. By injecting `IContentService` and `IContentTypeService` into an API controller, the raw data can be transformed into Block Grid JSON. It can then be saved to the target content item. {% code title="BlockGridTestController.cs" lineNumbers="true" %} ```csharp using Microsoft.AspNetCore.Mvc; using My.Site.Models; -using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; @@ -657,7 +762,7 @@ public class BlockGridTestController : Controller public ActionResult Create() { // get the item content to modify - IContent? content = _contentService.GetById(Guid.Parse("efba7b97-91b6-4ddf-b2cc-eef89ff48c3b")); + IContent? content = _contentService.GetById(Guid.Parse("7ed0bd1f-2a52-4b45-9811-2560b907fe48")); if (content == null) { return NotFound("Could not find the content item to modify"); @@ -679,43 +784,44 @@ public class BlockGridTestController : Controller }; // build the individual parts of the block grid data from the raw data + var contentData = new List(); + var settingsData = new List(); + var exposeData = new List(); var layoutItems = new List(); - var spotContentData = new List(); - var spotSettingsData = new List(); foreach (var data in rawData) { - // generate new UDIs for block content and settings - var contentUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid()); - var settingsUdi = Udi.Create(Constants.UdiEntityType.Element, Guid.NewGuid()); - - // create a new layout item - layoutItems.Add(new BlockGridLayoutItem(contentUdi, settingsUdi, data.ColumnSpan, data.RowSpan)); + // generate new keys for block content and settings + var contentKey = Guid.NewGuid(); + var settingsKey = Guid.NewGuid(); // create new content data - spotContentData.Add(new BlockGridElementData(spotContentType.Key, contentUdi) + var contentValues = new BlockGridValueData[] { - Data = new Dictionary - { - { "title", data.Title }, - { "text", data.Text }, - } - }); + new("title", "Umbraco.TextBox", data.Title), + new("text", "Umbraco.TextBox", data.Text), + }; + contentData.Add(new BlockGridElementData(spotContentType.Key, contentKey, contentValues)); // create new settings data - spotSettingsData.Add(new BlockGridElementData(spotSettingsType.Key, settingsUdi) + var settingValues = new BlockGridValueData[] { - Data = new Dictionary - { - { "featured", data.Featured ? "1" : "0" }, - } - }); + new("featured", "Umbraco.TrueFalse", data.Featured ? "1" : "0"), + }; + settingsData.Add(new BlockGridElementData(spotSettingsType.Key, settingsKey, settingValues)); + + // create a new expose item + exposeData.Add(new BlockGridExposeData(contentKey)); + + // create a new layout item + layoutItems.Add(new BlockGridLayoutItem(data.ColumnSpan, data.RowSpan, contentKey, settingsKey)); } // construct the block grid data from layout, content and settings var blockGridData = new BlockGridData( - new BlockGridLayout(layoutItems.ToArray()), - spotContentData.ToArray(), - spotSettingsData.ToArray()); + [.. contentData], + [.. settingsData], + [.. exposeData], + new BlockGridLayout([.. layoutItems])); // serialize the block grid data as JSON and save it to the "blockGrid" property on the content item var propertyValue = _serializer.Serialize(blockGridData); @@ -728,10 +834,8 @@ public class BlockGridTestController : Controller ``` {% endcode %} -For the above code `IContent? content = _contentService.GetById(1203);` change the id with your content node that is using the Block Grid. +For the above code `IContent? content = _contentService.GetById(Guid.Parse("efba7b97-91b6-4ddf-b2cc-eef89ff48c3b"));` change the id with your content node that is using the Block Grid. -10. In order to test this implementation, run the project and add `/umbraco/api/blockgridtest/create` after your domain name. If the result shows as **Saved** then check your content node and you will see the 2 spotElement contents. +10. To test this implementation, run the project and send a `POST` request to `/umbraco/api/blockgridtest/create` after your domain name. If the result shows as **Saved**, then check your content node, and you will see the 2 spotElement contents. ![Block Grid - Result](../../../images/BlockEditorContentCreated.png) - -_This can also be tested via Postman as well if preffered._