How to get nested blocks working in the panel

Hi there,

I want to create a custom block that has nested blocks inside it. Here is a simplified blueprint:

name: My Custom Block
fields:
  headline:
    type: writer
    marks: 
      - bold
  content_blocks:
    type: blocks
    fieldsets:
      - heading
      - text
      - video

Now I want to create an editable preview for the panel. My problem is, that I don’t know how to properly use the <k-blocks> element. I want it to function exactly like the root blocks inside a page. Here is what I have so far:

panel.plugin('diverently/my-custom-block', {
    blocks: {
        content: {
            template: `
                <div>
                    <k-writer
                        :inline="true"
                        :marks="['bold']"
                        :placeholder="field('headline').placeholder"
                        :value="content.headline"
                        @input="update({ headline: $event })"
                    />
                    <div>
                        <div v-for="item in content.content_blocks">
                            // What goes here?
                        </div>
                    </div>
                </div>
            `
        }
    }
})

Can someone help me with this?

Best regards,
Robert

See Nested blocks | Kirby CMS

Yeah, thanks, I saw that one. I guess you’re talking about this part specifically:

template: `
  <div @dblclick="open" class="faq">
    <h2>{{ content.headline }}</h2>
    <div v-html="content.text"></div>
    <dl v-for="item in content.blocks">
      <dt v-html="item.content.question"></dt>
      <dd v-html="item.content.answer"></dt>
    </dl>
  </div>
`

But this has only one nested (custom) block type. In my case there will be different block types possible, some default and some custom ones. Also the example from that article isn’t editable inside the preview.

Is there a way to have nested blocks be editable? And is it possible to do that without having to rebuild the default previews?

I’m trying to do the same thing. Did you ever figure this out?

The only other related post I found online also doesn’t offer any solution.

Not tested, but maybe you can use the block component? Kirby Panel

Hi @gmpreussner, no unfortunately I never figured this out. Now the client has to use the form in the slide over panel. Maybe some day :slight_smile:

This works for me as a very basic outline, using the example blocks from above (without the updating part, that is. Maybe it helps as a starting point:

name: My Custom Block
preview: mycustomblock
wysiwyg: true
fields:
  headline:
    type: writer
    marks:
      - bold
  content_blocks:
    type: blocks
panel.plugin('my/customblock', {
    blocks: {
        mycustomblock: {
            template: `
                <div>
                    <k-writer
                        :inline="true"
                        :marks="['bold']"
                        :placeholder="field('headline').placeholder"                        
                        :value="content.headline"
                        @input="update({ headline: $event })"
                    />
                    <div>
                        <div v-for="item in content.content_blocks">
                        <k-block :type="item.type" :content="item.content"></k-block>
                        </div>
                    </div>
                </div>
            `
        }
    }
})

I’m having trouble accessing field properties of nested blocks. I’m trying something along the line of

disclosure.yml :

name: field.blocks.disclosure.name
label: Disclosure
icon: bars

fields:
  details:
    label: Details
    type: writer
    placeholder: Add more details…

accordion.yml :

name: field.blocks.accordion.name
icon: map
fields:
  items:
    label: Items
    type: blocks
    fieldsets:
      - disclosure

index.js :


panel.plugin("my-custom/blocks", {
	blocks: {
		accordion: {
			computed: {
				items() {
					return this.content.items || {}
				},
			},
			methods: {
				detailsField( item ) {
					return item.field( "details" );
				},
			},
			template: `
				<div class="k-block-type-my-custom-accordion-item"
					v-for = "(item, index) in items"
					:key = "index"
				>
					<p>
						<k-writer
							ref = "details"
							:placeholder = "detailsField( item ).placeholder || 'Add some details'"
							:value = "item.content.details"
							@input = "updateItem( content, index, 'details', $event )"
						/>
					</p>
				</div>
			`
		}
	}
}

where this part

:placeholder = detailsField( item ).placeholder

fails.

I cannot find the documentation for the function

item.field()

i could dig deep into this._props.fieldset.tabs.content.fields but that doesn’t seem right.

Edit: This works:

computed: {
	disclosureFields() {
		return this.fieldset.tabs.content.fields.items.fieldsets.disclosure.tabs.content.fields
	},
},

and then use

:placeholder = "disclosureFields.details.placeholder

But is this the correct approach?