Search code examples
piranha-cms

Setting the Vue Component for a BlockGroup


I'm trying to build a custom component in Piranha called Table. It consists of a BlockGroup called TableBlock, which contains a BlockGroup called TableRowBlock, which itself contains a list of fields of type TableCellField.

I've never embedded a BlockGroup inside a BlockGroup before and not sure if it's possible, but I hope it is. A BlockGroup by default is rendered by the block-group (or block-group-horizontal?) Vue component in the admin, but I want to render it with my own custom Vue component.

It seems like even though I set the Component property on the BlockGroup, it ignores it and it still defaults to one of the default components for a BlockGroup, such as block-group or block-group-horizontal.

Is there any way to accomplish what I'm trying to do?

namespace Piranha.Extend.Blocks
{
    [BlockGroupType(Name = "Table", Category = "Content", Icon = "fas fa-images", Component = "table-block")]
    [BlockItemType(Type = typeof(TableRowBlock))]
    public class TableBlock : BlockGroup
    {
    }

    [BlockGroupType(Name = "Table Row", Category = "Content", Icon = "fas fa-images", Component = "table-row-block")]
    [BlockItemType(Type = typeof(TableCellField))]
    public class TableRowBlock : BlockGroup
    {
        public int RowNumber { get; set; }

        public override string GetTitle()
        {
            return "Row";
        }
    }
}

namespace Piranha.Extend.Fields
{
    [FieldType(Name = "TableCell", Shorthand = "Text", Component = "table-cell-field")]
    public class TableCellField : IField
    {
        public string Value { get; set; }
        public int ColumnNumber { get; set; }

        public string GetTitle()
        {
            return !string.IsNullOrEmpty(ColumnNumber.ToString()) ? ColumnNumber.ToString() : "";
        }
    }
}

Here's the "table-block" Vue component:

<template>
    <div :id="uid" class="block-group">
        <table>
            <template v-for="child in model.items">
                <component v-bind:is="child.meta.component" v-bind:uid="child.meta.uid" v-bind:toolbar="toolbar" v-bind:model="child.model"></component>
            </template>
        </table>
    </div>
</template>

<script>
    export default {
        props: ["uid", "toolbar", "model"],
        methods: {

        },
        mounted: function () {
            
        }
    }
</script>

Here's the "table-row-block" Vue component:

<template>
    <tr :id="uid" class="block-group">
        <template v-for="child in model.items">
            <component v-bind:is="child.meta.component" v-bind:uid="child.meta.uid" v-bind:toolbar="toolbar" v-bind:model="child.model" v-on:update-title="updateTitle($event)"></component>
        </template>
    </tr>
</template>

<script>
export default {
    props: ["uid", "toolbar", "model"],
    methods: {

    },
    mounted: function () {
        var self = this;
    }
}
</script>

Here's the "table-cell-field" Vue component:

<template>
    <td :id="uid">
        <input class="form-control" :placeholder="meta.placeholder" v-model="model.value" v-on:change="update()" type="text" />
        <input class="form-control" v-model="model.columnNumber" type="hidden" />
    </td>
</template>

<script>
    export default {
        props: ["uid", "model", "meta"],
        methods: {
            update: function () {
                
            }
        }
    }
</script>

Here's the error I'm getting: enter image description here


Solution

  • Unfortunately none of the things you’re trying to do is currently supported, that means:

    1. Block groups can’t contain other block groups, only blocks.
    2. Block groups can’t have custom vue components, they use the selected built in rendering in the manager.

    The second one would be easy to support, and could be added in a service release. The first one however couldn’t be added without serious redesign of the editor UI/UX since the built in model doesn’t support collections on multiple levels.

    The best solution with the current data model is to simply add a global field to the Table block that specifies the number of columns. This could then be used when rendering the custom block group component if support was added to this.