Use a custom renderer on a composite component
- Dominant language
- Java
- Stars
- 127
- Forks
- 59
- Avg merge
- 23h
- Merged PRs (30d)
- 7
Description
See discussion on "[jsr-314-open] Use a Renderer on a composite component"
Below there are extracts of this one:
Leonardo Uribe says:
The javadoc of Application.createComponent(FacesContext context, Resource
componentResource) says this:
".....Call UIComponent.setRendererType(java.lang.String) on the UIComponent
instance, passing "javax.faces.Composite" as the argument........"
Now suppose a custom composite component extending from UIInput, but
implementing NamingContainer/UniqueIdVendor. The component family in this case
is "javax.faces.Input". The result is the component will not work because the
renderer used for composite components assumes the family
"javax.faces.NamingContainer". This is ok, because the user just need to
register a custom renderer for its composite component under that
family/rendererType like the spec says.
The problem is why it is mandatory to set "javax.faces.Composite" as renderer
type. The javadoc should say:
"...If the renderer type is not set (return null), Call
UIComponent.setRendererType(java.lang.String) on the UIComponent instance,
passing "javax.faces.Composite" as the argument...". In that case, a user can
override the rendererType on the constructor and avoid this hack that works with
the current spec:
public void setRendererType(String rendererType)
{
//Ignore this call !
if (!"javax.faces.Composite".equals(rendererType))
{ super.setRendererType(rendererType); }
}
Why override the default Renderer and use a custom one? Let's suppose the
component proposed needs some custom code for converter, or for decode. The
right place to put that kind of code is the Renderer class, not the component,
but note it is possible to put that on the component class.
Does that sounds reasonable? should I create an issue for this one?
Ed Burns says:
LU> The problem is why it is mandatory to set "javax.faces.Composite" as
LU> renderer type. The javadoc should say:
LU> "...If the renderer type is not set (return null), Call
LU>
UIComponent.setRendererType(java.lang.String)<[file:///D:/jdk-1_5_0-doc/jsf20/mojarra-2.0.3-SNAPSHOT/docs/javadocs/javax/faces/component/UIComponent.html#setRendererType%28java.lang.String%29](file:///D:/jdk-1_5_0-doc/jsf20/mojarra-2.0.3-SNAPSHOT/docs/javadocs/javax/faces/component/UIComponent.html#setRendererType%28java.lang.String%29)>on
LU> the
LU> UIComponent instance, passing "javax.faces.Composite" as the argument...".
LU> In that case, a user can override the rendererType on the constructor and
LU> avoid this hack that works with the current spec:
I understand the problem you have uncovered. Take a look at the
renderkit docs for javax.faces.NamingContainer/javax.faces.Composite.
There are specific requirements in there that depend on the composite
component metadata specification.
I thought it would be toooooooo subtle to allow the Renderer to be
customized beause this contract must also be followed in the custom
renderer case.
LU> Why override the default Renderer and use a custom one? Let's
LU> suppose the component proposed needs some custom code for converter,
LU> or for decode. The right place to put that kind of code is the
LU> Renderer class, not the component, but note it is possible to put
LU> that on the component class.
Yes I understand that the Renderer is the right place for such things
but the chosen programming model for customization of composite
components is to override the top level component. Simple. If we're
going to change that I need a more compelling reason than correctness.
Leonardo Uribe says:
The current behavior of javax.faces.NamingContainer/javax.faces.Composite
renderer says that everything
inside the facet UIComponent.COMPOSITE_FACET_NAME should be rendered. But sometimes
the markup of the component changes according to its inner state. One simple
example is
h:commandLink. If this component is disabled, it should be rendered a
instead use .
Other example is tomahawk displayValueOnly property, that when is set to true,
only the value
needs to be rendered.
Ok, if I have a composite component the first thought is use c:if tag, but
remember that with
partial state saving enabled this tag is evaluated when the view is build, not
when it is
rendered. Other alternative is use a component that allows to render one child
at the time, and
it is on myfaces commons (mc:renderOne, old sandbox s:limitRendered). The third
alternative is
use a custom renderer. The example I'm trying to do is this (all non relevant
code has been removed:
public void encodeEnd(FacesContext context, UIComponent component)
throws IOException
{
UIComponent compositeFacet = (UIComponent) component
.getFacet(UIComponent.COMPOSITE_FACET_NAME);
CompositeInputHtml editor = (CompositeInputHtml) component;
if( HtmlRendererUtils.isDisplayValueOnly(editor) )
{ encodeDisplayValueOnly(context, editor); }
else if ( useFallback(editor) )
{ encodeEndFallBackMode(context, editor); }
else
{
if( ! isVisible(editor) )
{ encodeHidden(context, editor); }
else if( ! hasAnotherPropertyThatPreventsRenderThisOneCorrectly(
context ) )
{ compositeFacet.encodeAll(context); }
else
{ encodeEndFallBackMode(context, editor); }
}
}
It is possible to think in other cases, like a composite component like this:
......some html markup......
......some html markup......
......some html markup......
And use a custom renderer to control when one or other facet should be rendered.
Note that in fact, with the hack on the component class on setRendererType, it
is possible
to override the Renderer without problem, so for my particular problem I can
live with it.
The question is if the spec should enforce the use of
javax.faces.NamingContainer/javax.faces.Composite renderer for composite components
or not.
#### Environment
Operating System: All
Platform: All
#### Affected Versions
[2.0]
Contributor guide
Research direction
Start with the javadoc for Application.createComponent and the renderkit documentation for javax.faces.NamingContainer and javax.faces.Composite. Trace the renderer-type requirement described in the issue and compare it with the custom-renderer use cases in the discussion. Done means the specification and related documentation clearly resolve whether composite components may use a custom renderer while preserving the required contract.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- frontend, web-dev
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100