Conditionally render element's attribute in a composite component - jsf

I have the following composite component:
<?xml version="1.0" encoding="UTF-8"?>
<ui:component xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions"
xmlns:composite="http://java.sun.com/jsf/composite">
<composite:interface>
<composite:attribute required="true" name="field" />
<composite:attribute required="true" name="value" />
<composite:attribute required="false" name="size"/>
</composite:interface>
<composite:implementation>
...
<div class="wrapper">
<h:inputText value="#{cc.attrs.value}"
id="#{field.id}"
rendered="#{field.rendered}"
size="#{cc.attrs.size}">
</h:inputText>
<h:messages for="#{field.id}" styleClass="errorMessage"/>
</div>
...
</composite:implementation>
</ui:component>
The problem is that when I'm using this component without setting its size attribute, it still gets rendered as size=0 in the html input element.
What I want is to render the nested h:inputText's attribute only if it has a valid value (eg. not empty). Alternatively, I'd like to expose all attributes of the nested element if they are not overridden explicitly.
How would it be possible?

You can use JSTL <c:if> to build the view conditionally and <f:attribute> to specify an attribute separately:
<h:inputText ...>
<c:if test="#{not empty cc.attrs.size}">
<f:attribute name="size" value="#{cc.attrs.size}" />
</c:if>
</h:inputText>
An alternative is to specify a default for the composite component attribute:
<cc:attribute name="size" required="false" default="10" />

Additional to BalusC's post:
You must use
type="int" in the cc:attribute-tag :
cc:attribute name="maxlength" type="int"

I believe there is an alternate method for accessing attributes. I've used this with JSF 2 when accessing an attribute named with a java reserved keyword.
{cc.attrs['size']}

Related

Primefaces blockUI and composition

I'm using JSF 2.2, PF 5.3 and GlassFish 4.1.1.
I'm trying to centralize the blockUI content in my web application.
here the code of the my custom blockUI
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:cc="http://xmlns.jcp.org/jsf/composite"
xmlns:p="http://primefaces.org/ui">
<cc:interface>
<cc:attribute name="block" type="java.lang.String"/>
<cc:attribute name="trigger" type="java.lang.String"/>
</cc:interface>
<cc:implementation>
<p:blockUI block="#{cc.attrs.block}" trigger="#{cc.attrs.trigger}">
LOADING<br />
<p:graphicImage library="images" name="ajax-loader.gif"/>
</p:blockUI>
</cc:implementation>
and here the code in which I'm trying to apply this one
<h:form>
...
...
<p:dataTable id="myTable">
<p:column headerText="actions">
<p:commandButton class="triggerableFromBlockUI" action="#{action1}"/>
<p:commandButton class="triggerableFromBlockUI" action="#{action2}"/>
</p:column>
</p:dataTable>
...
...
<myTag:blockUI block="myTable" trigger="#(.triggerableFromBlockUI)"/>
</h:form>
but I see the following error
Cannot find component for expression "myTable".
If I use directly the p:blockUI all is working. Can you help me?
Here the solution found in the Prime Faces Forum
<myTag:blockUI block="#form:myTable" trigger="#(.triggerableFromBlockUI)"/>

Component inside Composite referencing another component inside other component

I created a Composite Component to emulate the Primefaces's Column, which instead render to components, its renderize to (I also created other components to emulate Primefaces's PanelGrid and Row to use DIVs instead Table and TR). The code is the following:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface>
<cc:attribute name="id" type="java.lang.String" required="false"/>
<cc:attribute name="span" type="java.lang.Integer" required="false" default="1" />
</cc:interface>
<cc:implementation>
<p:outputPanel id="#{cc.attrs.id}" layout="block"
styleClass="ui-grid-col-#{cc.attrs.span}">
<cc:insertChildren />
</p:outputPanel>
</cc:implementation>
</html>
My problem happens when I use a outputLabel referrecing a component to an outside's component:
<ipem:column span="2">
<p:outputLabel value="#{msg['precadastro.titulo.nome_fantasia']}" for="fantasia"/>
</ipem:column>
<ipem:column span="10">
<p:inputText id="fantasia" size="80" maxlength="100"
value="#{preCadastroMB.preCadastro.nomeFantasia}" />
</ipem:column>
When I wrote this, I got the message Cannot find component with identifier "fantasia" referenced from "painelCadastro:j_idt80:j_idt82:j_idt84". I need remove the for attribute in outputLabel.
I found some questions here in StackOverflow which are near my doubt. For example, in How to make a grid of JSF composite component? we have an outputLabel in the parent page which references a component inside a composite. However, in my case, both label as inputText are inside its own composite. In How to create a composite component for a datatable column? the label and inputText are both in the same composite.
We don't have this problem Column's Primefaces. How do they manage this?
Thanks,
Rafael Afonso

Create customizable components

I am new to JSF. We are building a web application using JSF with primefaces. We have lot of places where we need to display table. The table should have paging, column resizeable, in some places we need context menu on right click, etc.
I am able to implement this with dataTable component provided by primefaces. But I would like to create it as more customizable component. Some thing like reusable javascript/jquery (Jqgrid) plugin where we just set few property values which should be should be enough.
I would also want to do the similar way instead of writing the whole code for all the functionality, if a component is created which can be reused in all places and set parameters (Eg: columnResizable='true', columnSortable='true') which saves development time.
I am not getting any picture of how to accomplish it. If some one can guide that will be great. I am not expecting entire code, any idea of implementing this using JSF will be really appreciated.
You should use a composite component, you can pass as many parameters as you want and customize it accordingly using #{cc.attrs.param1} syntax. Here's a sample XHTML.
Composite component
<ui:component xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsp/jstl/core" xmlns:u="http://java.sun.com/jsf/composite/ui" xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html" xmlns:s="http://jboss.org/seam/faces" xmlns:p="http://primefaces.org/ui" xmlns:cc="http://java.sun.com/jsf/composite">
<cc:interface>
<cc:attribute name="tableId" />
<cc:attribute name="param1" />
<cc:attribute name="param2" default="false" />
<cc:attribute name="param3" required="true" />
</cc:interface>
<cc:implementation>
<p:dataTable id="#{cc.attrs.tableId}" rendered="#{cc.attrs.param2}" value="#{cc.attrs.param1}" var="result" emptyMessage="#{messages['global.noItemsFound']}">
<ui:include src="#{cc.attrs.param3}" />
</p:dataTable>
</cc:implementation>
</ui:component>
Using <c:if test="#{not empty cc.attrs.param4}"> or rendered attributes you can further customize your component
View
Let's call your composite myList.xhtml, then you could call it:
<u:myList param1="#{backingbean.results}" param2="true" id="list1" param3="/items/columns.xhtml" />
and don't forget to put a header in your view:
xmlns:u="http://java.sun.com/jsf/composite/ui"
columns.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:s="http://jboss.org/seam/faces" xmlns:u="http://java.sun.com/jsf/composite/ui"
xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui">
<p:column headerText="Name">
<h:outputText value="#{result.name}" />
</p:column>
<p:column headerText="Salary">
<h:outputText value="#{result.salary}" />
</p:column>
<p:column headerText="Age">
<h:outputText value="#{result.age}" />
</p:column>
</ui:composition>
An alternative to including a separate view for columns would be using <p:columns> in composite component and passing another list containing columns data as a parameter. Dynamic Columns

Using id-attribute in JSF 2 composite component with targets

I am trying to create a JSF 2.1 composite component for a button:
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:c="http://java.sun.com/jstl/core">
<composite:interface>
<composite:attribute name="id" required="true" type="java.lang.String" />
<composite:attribute name="label" required="true" type="java.lang.String" />
<composite:attribute name="action" method-signature="java.lang.String action()" targets="#{cc.attrs.id}" />
</composite:interface>
<composite:implementation>
<a4j:commandLink id="#{cc.attrs.id}">
<span style="linkButton"><h:outputText value="#{cc.attrs.label}" /></span>
</a4j:commandLink>
</composite:implementation>
</html>
The problem I have with this code is that it gives the following exception when the page is rendered:
java.lang.ClassCastException: javax.faces.component.UINamingContainer cannot be cast to javax.faces.component.ActionSource2
at com.sun.faces.application.view.FaceletViewHandlingStrategy$MethodRetargetHandlerManager$ActionRegargetHandler.retarget(FaceletViewHandlingStrategy.java:1536)
at com.sun.faces.application.view.FaceletViewHandlingStrategy.retargetMethodExpressions(FaceletViewHandlingStrategy.java:689)
at com.sun.faces.facelets.tag.jsf.CompositeComponentTagHandler.applyNextHandler(CompositeComponentTagHandler.java:201)
at org.richfaces.view.facelets.html.BehaviorsAddingComponentHandlerWrapper.applyNextHandler(BehaviorsAddingComponentHandlerWrapper.java:53)
at com.sun.faces.facelets.tag.jsf.ComponentTagHandlerDelegateImpl.apply(ComponentTagHandlerDelegateImpl.java:196)
...
When I replace the #{cc.attrs.id} in id and targets attribute with a defined String like myId then the component works as expected but this makes it not reusable in the same page and thus eliminates the wohle sense in creating a composite component in the first place.
Did I miss anything here?
In the JSF component tree, the #{cc.attrs.id} is already used by <cc:implementation> itself. You're not supposed to reuse any used component ID on another component. Your concrete functional requirement is unclear, the complaint "not reusable in the same page" makes really no sense as it works perfectly fine (have you actually tried it and investigated the produced HTML output?), so it's hard to understand what problem exactly you're facing. Perhaps you completely overlooked that composite components implicitly inherit from NamingContainer and already prepend their own id to those of children, like as <h:form>, <h:dataTable>, etc also do?
If your sole requirement is being able to reference the composite component from outside by ajax as in <f:ajax render="compositeId" />, then you need to wrap the body of <cc:implementation> in a plain vanilla HTML <span> or <div> as follows with the #{cc.clientId} instead:
<div id="#{cc.clientId}">
See also:
Rerendering composite component by ajax

What is the real conceptual difference between ui:decorate and ui:include?

It occurs ago me that ui:decorate is functionally the same as ui:include except that you can also pass ui:param and ui:define to the included file.
Am I crazy?
EDIT : Although in fact you can pass ui:param to a ui:include file too, it turns out I am already doing it. Maybe you can pass a ui:define as well, I will check and edit here.
The main difference between <ui:include> and <ui:decorate> is that the <ui:decorate> is intended to allow insertion of user-defined template components, while the <ui:include> is intended to include an existing and already-predefined template.
This indeed means that the <ui:decorate> supports <ui:define> for user-defined template components in its body and can insert it at the <ui:insert> place inside the template.
Here's a -somewhat clumsy- example to show where it can be used:
/WEB-INF/templates/field.xhtml
<ui:composition
xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
>
<h:outputLabel for="#{id}" value="#{label}" />
<ui:insert name="input" />
<h:message id="#{id}_message" for="#{id}" />
</ui:composition>
/page.xhtml
<h:panelGrid columns="3">
<ui:decorate template="/WEB-INF/templates/field.xhtml">
<ui:param name="label" value="Foo" />
<ui:param name="id" value="foo" />
<ui:define name="input">
<h:inputText id="foo" value="#{bean.foo}" required="true" />
</ui:define>
</ui:decorate>
<ui:decorate template="/WEB-INF/templates/field.xhtml">
<ui:param name="label" value="Bar" />
<ui:param name="id" value="bar" />
<ui:define name="input">
<h:selectBooleanCheckbox id="bar" value="#{bean.bar}" required="true" />
</ui:define>
</ui:decorate>
...
</h:panelGrid>
Note that it renders the components nicely in each cell of the panel grid. Again, this particular example is pretty clumsy, I'd just have used a tag file instead. Only if it was a larger section, e.g. a whole form whose e.g. its header or footer should be customizable, then an <ui:decorate> would have been appropriate.
Another major advantage of <ui:decorate> is that it allows you to use a composite component with a template. See also Is it possible to use template with composite component in JSF 2?

Resources