I'm working on integrating a JavaScript framework (Aurelia) for frontend components into our existing JSF application. I'm using JSF renderers to place the custom tags into the output, e.g.:
@FacesRenderer(componentFamily = "frontend.component", rendererType = "frontend.mytag")
public class MyTagRenderer extends Renderer {
@Override
public void encodeEnd(FacesContext context, UIComponent component) throws IOException {
final String tag = "my-tag";
int id = (Integer) component.getAttributes().get("id");
ResponseWriter writer = context.getResponseWriter();
writer.startElement(tag, component);
writer.writeAttribute("id.bind", id, null);
writer.endElement(tag);
}
}
The problem is that while initializing the JS framework I have to know which custom tags need to be bootstrapped. At first I tried doing this server-side, by adding the tagname as a property to my JSF frontend component class, setting it in the custom renderer and walking the JSF component tree to get a list:
class MyTagRenderer {
public void encodeEnd(FacesContext context, UIComponent component) {
...
((FrontendComponent) component).setTagName("my-tag:);
}
}
@ManagedBean
@RequestScoped
class FrontendBootstrapHandler {
public String getTagList() {
List<String> tags = walkRecursive(FacesContext.getCurrentInstance().getViewRoot());
return "'" + String.join("','", tags + "'";
}
}
However I found that the order in which JSF renders parts of the page is not entirely predictable, and sometimes the walkRecursive was called before setTagName.
For now I've settled on rendering a <script> snippet alongside each custom tag to keep the list of tags to bootstrap client-side, but this is hardly ideal. Can anybody offer me a more elegant solution?