Neos quicktip: create new references in dynamic locations
Von Matthias Klatte, veröffentlicht am 26.11.2020
Referencing other content or pages is a common thing when working with the Neos CMS.
A lesser known thing is that the reference-editor, where you select these other nodes, is able to create new nodes as well, if there was no match for your search term.
This is quite useful i.e. when adding tags to a blog article.
Unfortunately by default you can only specify a static path where these new nodes would need to be created.
That might not always satisfy our needs as we might want to allow the users to create collections of tags in a way where we don't know any absolute node path.
Think of a structure like that:
Blog
├ Settings
├ Directory (2020)
│ ├ Article 1
│ └ ...
└ ...
In this scenario we use a special node-type for different kinds of settings used throughout the blog. (We could maybe have these settings on the main "entry-point", however we want to remove clutter.)
In this example we would keep our tags as nodes on this settings page.
Let's recap the editor reference on the reference editor:
tags:
type: references
ui:
label: 'Tags'
inspector:
group: document
editorOptions:
nodeTypes: ['My.Website:Tag']
createNew:
path: /sites/yoursite/tags
type: 'My.Website:Tag'
We want to avoid setting this absolute path in the createNew
option.
Here the React UI comes to the rescue: it supports client-side evaluation of multiple configurations used in the inspector.
However first we need to provide the absolute path that the editor needs. We add a bit of fusion code when rendering the document that will use this editor:
prototype(V.P:BlogArticle) {
body {
# render to the content
blogMetadata = Neos.Fusion:Tag {
attributes {
id = 'neos-blog-metadata'
data-tag-path = ${q(node).closest('V.P:Blog').find('V.P:BlogSettings').find('tagContentCollection').property('_path')}
}
@if.inBackend = ${node.context.inBackend}
}
}
}
Now we can use this value in our property definition by simply querying the guest-frame for this markup:
tags:
type: references
ui:
inspector:
editorOptions:
# ...
createNew:
path: "ClientEval: document.querySelector('[name=neos-content-main]')?.contentDocument.querySelector('#neos-blog-metadata')?.dataset.tagPath"
(This javascript snippet uses optional chaining for brevity, which might not yet be available in every setup at the point of writing. It uses the IDs and attribute names used in the corresponding fusion code example above.)