Cwe
November 8, 2016, 10:28am
1
When fetching somecontroller.get(request, {contentId: siteConfig.footerId }).body from for example page controller, the somecontroller response body is not fully rendered into html, but contain component comments.
I’m guessing these component comments get handled in postProcess.
The problem is that since I’m including stuff from various controllers, the component comments reference components which are not part of the main controller. And you get a null pointer exception.
Is it possible to tell thymeleaf.render to do a full render?
Cwe
November 8, 2016, 2:27pm
2
Hmm there seems to be a bug/feature related to this aswell.
I’m writing replaceComponentComments(body)
to achieve a full render.
If I have a page P1 which uses page P2.get().body which in turn uses layout L1.get().body
Then L1.regions suddently have added P2’s regionName which looks like this:
"regions": {
"1": {
"components": [
{
"name": <snipped>,
"path": "P2RegionName/0/1/0",
"type": "part",
"descriptor": <snipped>,
"config": <snipped>
}
],
"name": "1"
},
The path should have been:
"path": "1/0",
This is a problem because L1 does not know anything about P2, and I’m trying to do a full render of L1 in L1…
Cwe
November 8, 2016, 2:29pm
3
I feel like I’m implementing a ugly hack to work around the fact thymeleaf.render does not do a full render.
Cwe
November 8, 2016, 2:32pm
4
Cwe
November 8, 2016, 2:45pm
5
I have an idea for another solution that should work.
In P1 instead of using
content.get({ key: P2.id })
I can do
httpClient.request({ url: portal.pageUrl({ id: P2.id }) });
That should give me a fully rendered P2, right?
I dunno, but I suspect running a request is slower than calling a controller directly?
Cwe
November 8, 2016, 2:51pm
6
Then I’ll pass along some request params to say which view I want.
Default view is full page, but in this case I only want the region.
Yup that should work.
Cwe
November 9, 2016, 7:57am
7
Getting on the train home I realize my mistake. I was assuming that component paths where relative to the region, when in fact they are relative to the page. So as long as I do all the “postProcessing” in the page controller rather in the layout controller, it should work out.
Cwe
November 9, 2016, 8:49am
8
I have now moved from java.lang.NullPointerException
to java.lang.StackOverflowError
hehe
Cwe
November 9, 2016, 2:07pm
9
Here is some of the code I ended up with:
const regexString = '<!--# COMPONENT (.+?) -->';
const firstMatchRegex = new RegExp(regexString);
const globalReplaceRegex = new RegExp(regexString, 'g');
export default class pageController {
processPart(component) {
const partName = Component.getName(component);
switch (partName) {
case 'partName1':
case 'partName2':
return Component.getController(component).get(this.request, { config: component.config }).body;
default:
throw new Error(`${pageName} page processPart does not support part component:${toStr(component)}`);
} // switch partName
}
processText(component) {
return `<section data-portal-component-type="text">${component.text}</section>`;
}
processLayout(component) {
const layoutName = Component.getName(component);
switch (layoutName) {
case 'layoutname':
return Component.getController(component).get(this.request, { component }).body;
default:
throw new Error(`${pageName} page processLayout does not support layout component:${toStr(component)}`);
} // switch layoutName
}
replaceComponentComments(htmlString) {
while(htmlString.match(firstMatchRegex)) {
htmlString = htmlString.replace(globalReplaceRegex, (match, path, offset, string) => {
const component = Component.getComponentWithPathInPage(path, this.page);
if (Component.isPart( component)) { return this.processPart( component); }
if (Component.isText( component)) { return this.processText( component); }
if (Component.isLayout(component)) { return this.processLayout(component); }
throw new Error(`${pageName} page replaceComponentComments does not support component:${toStr(component)}`);
}); // replace
} // while firstMatchRegex
return htmlString;
}
}
mer
November 18, 2016, 11:56am
10
We’re a bit unsure where you get the problem with rendering components? Are you trying to render a part from another page in error.js?
Cwe
November 18, 2016, 12:19pm
11
I have sort of made my own version of fragment (by using a page) which I call snippet.
The benefit of my version is that it can be edited WYSIWYG.
So actually the problem occurs when you render a page, from a page.
Either way replaceComponentComments works and I no longer have any problems.
It might render slower though, hmm my snippet are typically static, so I could cache them.
tsi
November 21, 2016, 2:03pm
12
Hmm fragments can be edited (corrected) wysiwyg too?
Cwe
November 21, 2016, 2:05pm
13
But can you edit it WYSIWYG?
Can you create a page template for a fragment of some part or layout?
tsi
November 21, 2016, 9:15pm
14
Not sure what you mean here? A fragment can definetly be edited wysiwyg - be sure to configure mappings so it renders with contextual design. See how this is done here: https://github.com/enonic/app-superhero-blog/blob/master/src/main/resources/site/site.xml
1 Like
Cwe
November 22, 2016, 8:04am
15
Interesting. We definetly have to try that out. Feels a bit like a “hidden” feature, in that you gotta know a lot before you figure that one out.
tsi
November 22, 2016, 8:12am
16
Cwe
November 22, 2016, 12:05pm
17
A benefit that my snippet has over fragments is that it can contain multiple layouts.
Since it’s simply region it can contain just about anything.
So I can have only 1 content selector in site.xml, and edit the snippet as I like afterwards.
With fragments I could get away with a single fragment selector, with maximum=“0”.
And add the fragments in order in the page controller/view.
But if I wanted to add layout fragments, I would have to edit the site configuration,
rather than simply editing the snippet.
tsi
November 29, 2016, 3:35pm
18
We are planning a “container” component type that will potentially address this issue too in the future