myfaces-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Leonardo Uribe (JIRA)" <...@myfaces.apache.org>
Subject [jira] [Commented] (MYFACES-4026) Composite Component cc.clientId not usable in custom tag
Date Tue, 16 Feb 2016 20:20:18 GMT

    [ https://issues.apache.org/jira/browse/MYFACES-4026?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15149243#comment-15149243
] 

Leonardo Uribe commented on MYFACES-4026:
-----------------------------------------

Call getClientId() during view build time is a bad practice. It will not work well, because
on build time, the component tree is being built, so the relationship between parent/children
could not be set according to the state saving mode used. Without PSS, the code could work,
because facelets does not build the component tree, but with PSS it will fail. 

The right way to do it is add a listener to PostAddToViewEvent and call getClientId() from
that position, but it depends on what are you doing.

The code inside getClientId() is performance sensitive (it is called tons of times per request),
so any new lines there will cause performance issues later.

> Composite Component cc.clientId not usable in custom tag
> --------------------------------------------------------
>
>                 Key: MYFACES-4026
>                 URL: https://issues.apache.org/jira/browse/MYFACES-4026
>             Project: MyFaces Core
>          Issue Type: Bug
>          Components: General
>    Affects Versions: 2.1.17
>            Reporter: Thomas Herzog
>            Assignee: Leonardo Uribe
>            Priority: Trivial
>         Attachments: demo.zip
>
>
> If you use the cc.clientId in a custom tag, then the wrong ids are generated. 
> {code:xml}
> <composite:implementation>
> 	<cure:grid id="#{cc.clientId}">
> 		<cure:gridRow>
> 			<cure:gridCol width="12">
> 				my col
> 			</cure:gridCol>
> 		</cure:gridRow>
> 	</cure:grid>
> </composite:implementation>
> {code}
> Here we need an id otherwise an update on this component will fail since there wouldn't
be an html node on the client side which contents can be replaced by an update. There are
some cases where the composite component is not allowed to define an div which holds the client
id.
> {code:xml}
> <composite:implementation>
> <!-- Would break grid container specification -->
> <div id="#{cc.clientid}">
> 		<cure:gridRow>
> 			<cure:gridCol width="12">
> 				my col
> 			</cure:gridCol>
> 		</cure:gridRow>
> <div>
> </composite:implementation>
> {code}
> We think this is caused by the fact that the cc.clientId is accessed during build view
time and gets cached in the UIComponentBase. At this time the cc.clientId is empty. This seems
to be a common issue, because cc.clientId can never be accessed at build view time.
> {code:title="UIComponentBase#getClientId"}
>     @Override
>     public String getClientId(FacesContext context)
>     {
>         if (context == null)
>         {
>             throw new NullPointerException("context");
>         }
>         if (_clientId != null)
>         {
>             return _clientId;
>         }
> ...
> }
> {code}
> {code:xml|title="one of the custom tags we use"}
> <ui:composition
>     xmlns:c="http://java.sun.com/jsp/jstl/core"
>     xmlns:f="http://java.sun.com/jsf/core"
>     xmlns:h="http://java.sun.com/jsf/html"
> 	xmlns:p="http://primefaces.org/ui"
>     xmlns:ui="http://java.sun.com/jsf/facelets">
>     
>     <c:set var="styleClass" value="#{not empty styleClass ? styleClass : ''}" />
>     <c:set var="style" value="#{not empty style ? style : ''}" />
>     <c:set var="rendered" value="#{not empty rendered ? rendered : true}" />
>     <c:set var="isFormRow" value="#{not empty isFormRow and isFormRow}" />
> 	
> 	<c:if test="#{not empty id}">
> 		<h:panelGroup id="#{id}" layout="block" styleClass="#{isFormRow ? 'form-row' : ''}
#{styleClass} ui-grid-row" style="#{style}" rendered="#{rendered}">
> 			<ui:insert/>
> 		</h:panelGroup>
> 	</c:if>
> 	
> 	<c:if test="#{empty id}">
> 		<h:panelGroup layout="block" styleClass="#{isFormRow ? 'form-row' : ''} #{styleClass}
ui-grid-row" style="#{style}" rendered="#{rendered}">
> 			<ui:insert/>
> 		</h:panelGroup>
> 	</c:if>
> 	
> </ui:composition>
> {code}
> {code:html|title="resulting html"}
> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
> <html xmlns="http://www.w3.org/1999/xhtml">
>    <head></head>
>    <body>
>       <form id="myForm1" name="myForm1" method="post" action="/jsf2-basic-portlet/index.xhtml"
enctype="application/x-www-form-urlencoded">
>          <div id="composite1:composite1" class=" ui-grid ui-grid-responsive">
>             <div class="  ui-grid-row">
>                <div class=" ui-grid-col-12">
>                   my col
>                </div>
>             </div>
>          </div>
>          <input type="hidden" name="myForm1_SUBMIT" value="1" /><input type="hidden"
name="javax.faces.ViewState" id="javax.faces.ViewState" value="puXzCX78lsGwm5D7TAEgUKup9vm0hFpybGfw7y1R85EQt46s"
/>
>       </form>
>       <form id="myForm2" name="myForm2" method="post" action="/jsf2-basic-portlet/index.xhtml"
enctype="application/x-www-form-urlencoded"><span id="myForm2:composite2:myOutputText">OutputText</span><input
type="hidden" name="myForm2_SUBMIT" value="1" /><input type="hidden" name="javax.faces.ViewState"
id="javax.faces.ViewState" value="puXzCX78lsGwm5D7TAEgUKup9vm0hFpybGfw7y1R85EQt46s" /></form>
>    </body>
> </html>
> {code}
> I have an sample which I could provide but here is no option to upload it.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Mime
View raw message