To load the extension running locally (aio app run) in browser https://experience.adobe.com/#/@acsaem/aem/editor/canvas/author-p10961-e880305.adobeaemcloud.com/content/eaem-dev-eds/index/dynamic-dropdown.html?devMode=true&ext=https://localhost:9080
DropDown Extension in UE
Data Saved in CRX
Solution
1) For detailed instructions on setting up Universal Editor Extension and Publishing to your Org check this post, steps below load it from a locally running app so https://localhost:9080
2) Open terminal, login to aio and create an app. While going through the prompts make sure you select the Universal Editor Extension Template and Add a Custom Renderer...
> aio login
> aio app init eaem-ue-rr-dynamic-dropdown
3) Add the following code in eaem-ue-rte-open-new-tab\src\universal-editor-ui-1\web-src\src\components\ExtensionRegistration.js, make note of the dataType set to eaem:dynamic-select-field, creating it...
import { Text } from "@adobe/react-spectrum";
import { register } from "@adobe/uix-guest";
import { extensionId } from "./Constants";
import metadata from '../../../../app-metadata.json';
function ExtensionRegistration() {
const init = async () => {
const guestConnection = await register({
id: extensionId,
metadata,
methods: {
canvas: {
getRenderers() {
return [
{
extension: extensionId,
dataType: 'eaem:dynamic-select-field',
url: '/index.html#/eaem-dynamic-select-field'
}
];
},
},
},
});
};
init().catch(console.error);
return <Text>IFrame for integration with Host (AEM)...</Text>
}
export default ExtensionRegistration;
4) Add a route /index.html#/eaem-dynamic-select-field for the extension in src\universal-editor-ui-1\web-src\src\components\App.js
<Route exact path="eaem-dynamic-select-field" element={<EaemDynamicSelectField />} />
5) Add the Dynamic Dropdown code in src\universal-editor-ui-1\web-src\src\components\EaemDynamicSelectField.js for executing a Query Builder query to read the top level folders in /content/dam and fill the dropdown...
import React, { useState, useEffect, useRef } from 'react'
import { attach } from "@adobe/uix-guest"
import { Provider, defaultTheme, View, ComboBox, Item } from '@adobe/react-spectrum'
import { extensionId } from "./Constants"
export default function EaemDynamicSelectField () {
const [guestConnection, setGuestConnection] = useState()
let [value, setValue] = useState(null);
const [folders, setFolders] = useState([]);
const [loading, setLoading] = useState(true);
const FOLDERS_QUERY = "/bin/querybuilder.json?" +
"path=/content/dam" +
"&type=sling:Folder" +
"&property=hidden" +
"&property.operation=not" +
"&path.flat=true" +
"&p.limit=10"
const fetchRootFolders = async (AEM_HOST, connection) => {
const foldersQueryUrl = `${AEM_HOST}${FOLDERS_QUERY}`;
const requestOptions = {
headers: {
'Authorization': `Bearer ${connection.sharedContext.get("token")}`
}
};
const response = await fetch(foldersQueryUrl, requestOptions)
const folderList = (await response.json()).hits?.map(hit => ({
path: hit.path,
title: hit.title
})) || [];
return (folderList);
};
const getAemHost = (editorState) => {
return editorState.connections.aemconnection.substring(editorState.connections.aemconnection.indexOf('xwalk:') + 6);
}
useEffect(() => {
(async () => {
const connection = await attach({ id: extensionId })
setGuestConnection(connection);
const model = await connection.host.field.getModel();
console.log("Dropdown model.name----------->", model.name);
setValue(await connection.host.field.getValue() || '');
const editorState = await connection.host.editorState.get();
if(editorState){
const folderList = await fetchRootFolders(getAemHost(editorState), connection);
setFolders(folderList);
setLoading(false);
document.body.style.height = '200px';
}
})()
}, [])
const handleSelectionChange = (newValue) => {
setValue(newValue);
guestConnection?.host.field.onChange(newValue);
}
return (
<Provider theme={defaultTheme} colorScheme='dark' height='100vh'>
<View padding='size-200' UNSAFE_style={{ overflow: 'hidden' }}>
<ComboBox selectedKey={value} onSelectionChange={handleSelectionChange} label="Select Root Folder" isDisabled={loading} width="100%">
{folders.map(folder => (
<Item key={folder.path}>{folder.title}</Item>
))}
</ComboBox>
</View>
</Provider>
)
}
6) Set the custom dataType as "component": "eaem:dynamic-select-field" in your Block Model blocks\experience-aem-dynamic-select\_experience-aem-dynamic-select.json
{
"definitions": [
{
"title": "Experience AEM Dynamic Select",
"id": "eaem-dynamic-select",
"plugins": {
"xwalk": {
"page": {
"resourceType": "core/franklin/components/block/v1/block",
"template": {
"name": "Experience AEM Dynamic Select",
"model": "eaem-dynamic-select"
}
}
}
}
}
],
"models": [
{
"id": "eaem-dynamic-select",
"fields": [
{
"component": "text",
"valueType": "string",
"name": "eaemText",
"label": "Text"
},
{
"component": "eaem:dynamic-select-field",
"name": "eaemDynamicSelect",
"label": "Experience AEM Dynamic Select",
"valueType": "string"
}
]
}
],
"filters": []
}
7) The block rendering might need some decoration to show the selected path as regular text, so add the following code in blocks\experience-aem-dynamic-select\experience-aem-dynamic-select.js
export default async function decorate(block) {
const buttonContainers = block.querySelectorAll('.button-container');
buttonContainers.forEach(container => {
const link = container.querySelector('a');
if (link) {
const textContent = link.textContent;
container.innerHTML = "Selected root folder: " + textContent;
container.classList.remove('button-container');
}
});
}



No comments:
Post a Comment