0

I used to have a bunch of <ui:composition> templates and include them by

<ui:include src="${bean.type}.xhtml">
    <ui:param name="model" value="#{model}"/>
</ui:include>

${bean.type} gave the relative path to the template with the name. For example,

/a/b/c/table
/a/c/d/timeline

Now I am refactoring them to <ui:component>s

<cc:interface componentType="table">
    <cc:attribute name="model" type="my.company.Model" required="true"/>
</cc:interface>

<cc:implementation>
    <!-- -->
</cc:implementation>

or considering the option of defining the markup in the encodeXXX methods

class Widget extends UIComponentBase {}
class Table extends Widget {}
class TimeLine extends Widget {}

meaning I will end up with components

mycompany:table
mycompany:timeline

At the moment, I can't declare them having only their name coming from the bean's property

<mycompany:${bean.type} model="#{model}" />
<!-- this obviously doesn't work, but nicely illustrates the idea -->

I don't want to to the rendered magic rendering a certain tag only if the property matches the type. I am looking for a scalable solution because the hierarchy of the custom components is huge and I don't want to just list all of them in the template

<mycompany:table rendered="${bean.type == 'table'}" />
<mycompany:timeline rendered="${bean.type == 'timeline'}" />
<!-- and a lot more -->

I was looking for some kind of a tag/component resolver that I would give an "abstract" tag to

<mycompany:widget model="#{model}">

and it would resolve it to the proper widget subclass taking into account #{bean.type}, similarly to what Application#createComponent(context, name) does.

Thanks.

Related:

jsf dynamic tag from string

Andrew Tobilko
  • 48,120
  • 14
  • 91
  • 142
  • 2
    So you're looking for something like this? https://stackoverflow.com/q/5713718 Related: https://stackoverflow.com/q/6822000 – BalusC Apr 05 '20 at 21:05
  • BalusC knows all existing Q/A by hart, I only 10%... So while I was looking for it, he already found it. – Kukeltje Apr 05 '20 at 21:58
  • @BalusC I read both of them before posting the question. Actually that's what I'd like to avoid - I don't want a huge `c:choose` listing all my components (around 20) in one place. I am looking something that would resolve it automatically based on a property (or a method that would map that property to a valid component name). The idea is similar to `` though I can't place an expression there – Andrew Tobilko Apr 05 '20 at 22:48
  • @BalusC essentially, `FacesContext context = FacesContext.getCurrentInstance(); UIComponent component = context.getApplication().createComponent("org.primefaces.component.SelectManyMenu"); component.encodeAll(context);` (replace `"...SelectManyMenu"` with my `#{bean.type}`) is what you'd like to achieve (but on the template side) – Andrew Tobilko Apr 05 '20 at 22:54
  • With a good tag file you just include a `mypref:form` – Kukeltje Apr 06 '20 at 05:48
  • i think overriding the default `Renderer` (see [this](https://stackoverflow.com/questions/4605401/jsf-2-0-how-to-override-base-renderers-with-custom-ones) question) and replacing the the `startElement`/`endElement` values with your values from the bean could do the thing – fuggerjaki61 Apr 06 '20 at 08:06
  • You basically need to modify or replace Facelets in order to be able to do this. In JSF the view declaration language is pluggable. – BalusC Apr 06 '20 at 10:16

0 Answers0