Enonic version: 7.8.0
OS: OSX
Hello and happy new year,
We are working on a headless implementation and itβs going very well.
We use the menu library in our previous implementation to render the menu and get the structure of the menu.
Now I would like to use this in an enonic HTTP service. But when I run the function: getMenuTree()
I get an empty result. I tried running it in different contexts and with different parameters.
But no matter what I try I get an empty result. Is it possible to retrieve this structure in a HTTP service?
Or should I look at another direction.
Any tips would help me a bunch!
Kind regards,
Mark
Alan
January 10, 2022, 8:43am
2
We had a very similar discussion in a Slack thread in our community slack, but Iβm not sure how it ended up. Maybe itβs worth asking the original author how he solved it.
pkw
January 10, 2022, 8:58am
3
Just took a look at the lib-menu code.
Looks like it returns an empty menu if the content is not set.
function getSubMenus(parentContent, levels = 1, params = {}) {
//default properties
const settings = {
urlType: params.urlType == "absolute" ? "absolute" : "server",
returnContent: params.returnContent != undefined ? params.returnContent : false,
query: params.query ? params.query : "",
};
let currentContent = libs.portal.getContent();
// In controllers without content return an empty menu
if (currentContent) {
return iterateSubMenus(parentContent, levels);
} else {
return [];
}
function iterateSubMenus(parentContent, levels) {
const subMenus = [];
if (parentContent.type === "portal:site" && isMenuItem(parentContent)) {
I donβt think it would be difficult to change the lib to work headless.
Want me to create a feature request to add headless support?
1 Like
If thatβs not too much trouble that would be great!
Thank you.
Kind regards,
Mark
I did not know there was a community slack, iβll definitely join.
Thanks!
pkw
January 11, 2022, 1:31pm
6
Got a tip by the teach lead at our office:
If you are using headless previusly it might be simpler is extend Gullotine API by exposing a getMenu field?
The correct context is set so works without any changes to lib-menu.
asi
January 11, 2022, 4:03pm
7
Hi @Markvds ,
I did not figure out how to do that in HTTP service for now. But it can be done in Controller. Below you can find the example how to extend Guillotine, for instance add getMenuItems
field to some type.
const guillotineLib = require("/lib/guillotine");
const graphqlPlaygroundLib = require("/lib/graphql-playground");
const menuLib = require("/lib/menu");
const graphQlLib = require("/lib/graphql");
β
//ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Constants
//ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
const CORS_HEADERS = {
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Methods": "POST, OPTIONS",
"Access-Control-Allow-Origin": "*",
};
β
function resolveMenuItems() {
// to do some transformation of menuItems if needed
return menuLib.getMenuTree(1);
}
β
//ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// Methods
//ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
exports.options = function () {
return {
contentType: "text/plain;charset=utf-8",
headers: CORS_HEADERS,
};
};
β
exports.get = function (req) {
if (req.webSocket) {
return {
webSocket: {
data: guillotineLib.createWebSocketData(req),
subProtocols: ['graphql-ws']
}
};
}
β
let body = graphqlPlaygroundLib.render();
return {
contentType: "text/html; charset=utf-8",
body: body,
};
};
β
exports.post = function (req) {
let input = JSON.parse(req.body);
β
let params = {
query: input.query,
variables: input.variables,
schemaOptions: {
creationCallbacks: {
'<CONTENTENT_TYPE_NAME>': function (context, params) {
params.fields.getMenuItems = {
type: graphQlLib.Json,
resolve: function (env) {
return resolveMenuItems();
}
}
}
}
}
};
β
return {
contentType: 'application/json',
headers: CORS_HEADERS,
body: guillotineLib.execute(params)
};
};
β
exports.webSocketEvent = guillotineLib.initWebSockets();
Also you can add some parameter to context
argument of the execute
function, for instance:
exports.post = function (req) {
let input = JSON.parse(req.body);
let params = {
query: input.query,
variables: input.variables,
context: {
menus: menuLib.getMenuTree(1)
}
};
return {
contentType: 'application/json',
body: guillotineLib.execute(params)
};
};
this parameter will be available for any field in the resolve
function using env.context
, for instance, env.context.menus
.
I hope this information will be useful for you.
Best regards,
Anatol
1 Like
tsi
January 12, 2022, 8:52am
8
1 Like
Iβm going to try this! Thank you so much!
Markvds
January 12, 2022, 8:59am
10
This sounds perfect, passing a context or content id makes the lib way more flexible.
tsi
March 23, 2022, 9:01am
11
Hi all.
This has been released: Menu lib - Enonic Market