JSF 2.0 - Myfaces have problems rendering composite components - jsf-2

Some days ago I've changed mojarra to myfaces to solve this problem, now I'm having an strange problem rendering my composite components, they simply aren't rendered the second time I open one popup (the popup is a composite component too).
The first time, as you can see in fieldset, all is rendered ok:
then I click in "CANCELAR" (cancel) button, and the second time, none of my composite components, except the dialog, is rendered:
when I've looked at log, I found these messages:
[#|2012-04-10T15:22:00.681-0300|SEVERE|glassfish3.1.1|org.apache.myfaces.renderkit.html.HtmlCompositeComponentRenderer|_ThreadID=19;_ThreadName=Thread-2;|facet UIComponent.COMPOSITE_FACET_NAME not found when rendering composite component prevenda:popupPreVenda:j_id_2uz|#]
[#|2012-04-10T15:22:00.684-0300|SEVERE|glassfish3.1.1|org.apache.myfaces.renderkit.html.HtmlCompositeComponentRenderer|_ThreadID=19;_ThreadName=Thread-2;|facet UIComponent.COMPOSITE_FACET_NAME not found when rendering composite component prevenda:popupPreVenda:inputRazaoSocial|#]
[#|2012-04-10T15:22:00.685-0300|SEVERE|glassfish3.1.1|org.apache.myfaces.renderkit.html.HtmlCompositeComponentRenderer|_ThreadID=19;_ThreadName=Thread-2;|facet UIComponent.COMPOSITE_FACET_NAME not found when rendering composite component prevenda:popupPreVenda:j_id_2vi|#]
[#|2012-04-10T15:22:00.685-0300|SEVERE|glassfish3.1.1|org.apache.myfaces.renderkit.html.HtmlCompositeComponentRenderer|_ThreadID=19;_ThreadName=Thread-2;|facet UIComponent.COMPOSITE_FACET_NAME not found when rendering composite component prevenda:popupPreVenda:j_id_2vn|#]
[#|2012-04-10T15:22:00.686-0300|SEVERE|glassfish3.1.1|org.apache.myfaces.renderkit.html.HtmlCompositeComponentRenderer|_ThreadID=19;_ThreadName=Thread-2;|facet UIComponent.COMPOSITE_FACET_NAME not found when rendering composite component prevenda:popupPreVenda:j_id_2vs|#]
as you can see, the problem is that myfaces can't find a facet in composite component...
The only composite component that uses facets is hrgi:popup:
<c:interface>
<c:attribute name="titulo" default="sem titulo" required="false"/>
<c:attribute name="renderizar" default="false" required="false"/>
<c:attribute name="modal" default="true" required="false"/>
<c:attribute name="bordaConteudo" default="true" required="false"/>
<c:facet name="cabecalho" required="false"/>
<c:facet name="conteudo" required="true"/>
<c:facet name="botoes" required="true"/>
</c:interface>
<c:implementation>
<h:outputStylesheet library="css" name="hrgiPopup.css" target="head"/>
<h:outputStylesheet library="css" name="clearfix.css" target="head"/>
<h:outputScript library="js" name="hrgiPopup.js" target="head"/>
<h:panelGroup layout="block" rendered="#{cc.attrs.renderizar}"
class="hrgi-dialog-panel clearfix">
<h:panelGroup layout="block" class="hrgi-dialog-overlay clearfix" rendered="#{cc.attrs.modal}"></h:panelGroup>
<h:panelGroup id="popup" layout="block" class="hrgi-dialog-box clearfix">
<h:panelGroup layout="block" class="hrgi-dialog-title clearfix">
<h:outputText style="float:left" value="#{cc.attrs.titulo}"/>
</h:panelGroup>
<h:panelGroup layout="block" class="hrgi-dialog-content clearfix">
<c:renderFacet name="cabecalho" required="false"/>
<h:panelGroup layout="block" class="hrgi-dialog-background clearfix"
rendered="#{cc.attrs.bordaConteudo}">
<c:renderFacet name="conteudo" required="true"/>
</h:panelGroup>
<h:panelGroup layout="block" class="clearfix" rendered="#{not cc.attrs.bordaConteudo}">
<c:renderFacet name="conteudo" required="true"/>
</h:panelGroup>
<c:renderFacet name="botoes" required="true"/>
<script type="text/javascript">
cercarEventoTab("#{cc.clientId}:popup");
</script>
</h:panelGroup>
</h:panelGroup>
</h:panelGroup>
</c:implementation>
Is this a bug of MyFaces?? Mojarra doesn't show any problem like this!
UPDATED
The problem just happens when user clicks "CANCELAR" button... The action call this code to clear the fields and close the dialog:
public void cancelar(ActionEvent evento){
fechar();
UIComponent componente=evento.getComponent().getParent().getParent().getParent();
componente.getFacet("conteudo").getChildren().clear();
}
this code was adapted from the approaches you can see here. In this case, only components inside facet conteudo are recreated. Works fine, except with the my composite components.

The code in MyFaces is ok. The log suggest org.apache.myfaces.renderkit.html.HtmlCompositeComponentRenderer cannot find the c:implementation entry in your composite component file, Since 2.1.6, some changes were done to prevent use '/' characters inside libraryName (see MYFACES-3454 for details). A web config param (org.apache.myfaces.STRICT_JSF_2_ALLOW_SLASH_LIBRARY_NAME) was added to enable the backward behavior, but note the new behavior is mentioned in a explicit way inside the spec.
If that doesn't work, please try create a simple demo app reproducing the bug and create an issue in MyFaces Issue Tracker. In that way, there are better chances that it could get solved in a future release.
UPDATE
I tried to reproduce it with the information provided without success. The problem is the call to
componente.getFacet("conteudo").getChildren().clear();
That code remove all components inside the facet, and MyFaces is smart enought to remember the components that were removed. When the view is restored, MyFaces algorithm builds the view as in the first request and then remove the components to restore the state correctly. This behavior is expected, so there is no bug in MyFaces code. Instead, I suppose the previous behavior described is a bug in Mojarra, and you should change your code to reset your input components in other way, maybe clearing the values inside the bean, or creating a method expression attribute in your composite component that can be called when cancel operation occur and clear the required input fields. There is a lot of ways to do it.

I don't know why, but after I've created some class to handle exceptions, this problem disappeared...
public class HRGIExceptionHandler extends ExceptionHandlerWrapper {
private ExceptionHandler wrapped;
public HRGIExceptionHandler(ExceptionHandler wrapped) {
this.wrapped = wrapped;
}
#Override
public ExceptionHandler getWrapped() {
return wrapped;
}
#Override
public void handle() throws FacesException {
Iterator i = getUnhandledExceptionQueuedEvents().iterator();
while (i.hasNext()) {
ExceptionQueuedEvent event = (ExceptionQueuedEvent) i.next();
ExceptionQueuedEventContext context = (ExceptionQueuedEventContext)event.getSource();
Throwable t = context.getException();
try{
t.printStackTrace();
}finally{
i.remove();
}
}
getWrapped().handle();
}
}
and
public class HRGIExceptionHandlerFactory extends ExceptionHandlerFactory {
private ExceptionHandlerFactory parent;
public HRGIExceptionHandlerFactory(ExceptionHandlerFactory parent) {
this.parent = parent;
}
#Override
public ExceptionHandler getExceptionHandler() {
ExceptionHandler result = new HRGIExceptionHandler(parent.getExceptionHandler());
return result;
}
}
finally I've added this to faces.config:
<factory>
<exception-handler-factory>com.hrgi.web.erp.HRGIExceptionHandlerFactory</exception-handler-factory>
</factory>

Related

Updating a component with binding (JSF2 + PrimeFaces 5.0.2) [duplicate]

This question already has answers here:
How does the 'binding' attribute work in JSF? When and how should it be used?
(2 answers)
Closed 6 years ago.
I have some trouble dealing with PrimeFaces 5.0 and a panelGroup with "binding". I know, "binding" sucks, but I'm working with a legacy system and believe me, it's truly hard to make it the right way, without "binding".
So, when I click mi link, the getter of the "binding" property is called before the "action", then the action is called, and after all the "update". But, the component is not properly updated.
Even if I make it to run the "action" before the getter of the binding, and the getter is returning the right stuff, this particular component is not updated.
I have more components without binding which are updated properly, but not the one with "binding".
UPDATE:
Here is the rest of the code. flag starts with "false" value.
The page always print "READ ONLY".
Somepage.xhtml
<h:form id="frm">
<p:commandLink value="#{messages.Guardar}" id="bt_Guardar" action="#{myBean.flagFalse}" update="someid" />
<p:commandLink value="#{messages.Editar}" id="bt_Editar" action="#{myBean.flagTrue}" update="someid" />
<h:panelGroup id="someid" layout="block">
<h:panelGroup id="panelCamposTD" layout="block" binding="#{myBean.someStuff}" ></h:panelGroup>
</h:panelGroup>
</h:form>
And my myBean, wich is a SessionScoped bean (because it comes from a legacy system)
#ManagedBean(name="myBean")
#SessionScoped
public class MyBean implements Serializable{
private static final long serialVersionUID = 7628440827777833854L;
private boolean flag = false;
public void flagFalse(){
flag = false;
}
public void flagTrue(){
flag = true;
}
public HtmlPanelGroup getSomeStuff(){
HtmlPanelGroup pg = new HtmlPanelGroup();
HtmlOutputText t = new HtmlOutputText();
if (flag){
t.setValue("EDITED");
}else{
t.setValue("READ ONLY");
}
pg.getChildren().add(t);
return pg;
}
public void setSomeStuff(HtmlPanelGroup pg){
return;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
You should avoid bindings to managed beans with session scope. This can cause a lot of touble:
JSF 2.0 Spec
3.1.5 Component Bindings
[...]
Component bindings are often used in conjunction with JavaBeans that are dynamically instantiated via the Managed Bean Creation facility (see Section 5.8.1 “VariableResolver and the Default VariableResolver”). It is strongly recommend that application developers place managed beans that are pointed at by component binding expressions in “request” scope. This is because placing it in session or application scope would require thread-safety, since UIComponent instances depends on running inside of a single thread. There are also potentially negative impacts on memory management when placing a component binding in “session” scope.
There are two solutions which could avoid the binding:
In this solution, the output text is always visible and just get a different text from the backed bean:
<h:panelGroup id="someid" layout="block">
<h:panelGroup id="panelCamposTD" layout="block">
<h:outputText value="#{myBean.flaggedText}"></h:outputText>
</h:panelGroup>
</h:panelGroup>
Add the getter to the backed bean:
public String getFlaggedText(){
if (flag){
return "EDITED";
}else{
return "READ ONLY";
};
}
The other option is to put both output texts in the front end and hide one of them:
<h:panelGroup id="someid" layout="block">
<h:panelGroup id="panelCamposTD" layout="block">
<h:outputText value="EDITED" rendered="#{myBean.flag}"></h:outputText>
<h:outputText value="READ ONLY" rendered="#{not myBean.flag}"></h:outputText>
</h:panelGroup>
</h:panelGroup>

Getting correct parent ID in composite components

For partial updating my composite components, I have some problems finding the correct parent IDs. e.g. if my component is inside of a tabView
<p:tabView id="foo">
<p:tab>
<stg:mycomponent id="bar" />
</p:tab>
</p:tabView>
Now I need the String :foo:bar to find the correct parts, that I want to update. Via #{cc.id} I just get bar, so this does not work for me.
However, I tried to achieve this by some kind of dirty hack by adding a attribute to my component like this
<composite:attribute
name="parentId"
default=":#{component.namingContainer.parent.namingContainer.clientId}"
/>
If I hand over the String :foo:bar to parentId everything works fine, but of course that's not what I really want to do. I do not want to force the user of my component to hand over this ID.
But now the problem: If I do not hand over a parentId, I only can use my attribute in the "first level" of my component. If there are some kind of "nested IDs" then #{cc.attrs.parentId} is evaluated e.g. to foo:bar (which is nice) but also foo:bar:fooBar or somethin like that, depending on where #{cc.attrs.parentId} is located in my code.
I hope it's comprehensible what my problem is and what I am exactly asking for. If not, please leave a comment.
I am using primefaces 3.5 and JSF 2.1 (Mojarra)
If I understand, you need to update parts of a composite component within the composite component itself. Normally you don't need to know the parents IDs to achieve this.
As you are setting id on a primefaces component, you can update it with primefaces using the same id (without any :container:etc prefix) as long as your update is in the same scope.
Here is an example (see source below).
Observe the generated id's in the HTML page produced by JSF in the first tab:
First span : id="static" (raw html id, not PF, not unique in the document)
Second span : id="myform:tv1:comp1:static2" (PF-generated to ensure id is unique in the document)
Third span : id="myform:tv1:comp1:dynamic" (PF-generated, unique)
poll component use the id "myform:tv1:comp1:dynamic", even if we only provide "dynamic" in the source.
The parents does not need to know the ID of the component part to be updated
The component does not need to know the IDs of its parents/containers
Please note generated IDs on the second tab. PrimeFaces does its job by naming them unique.
Sample composite component:
<composite:interface>
<composite:attribute name="label" />
</composite:interface>
<composite:implementation>
<h1><h:outputText value="#{cc.attrs.label}"/></h1>
<span id="static1">
Static : #{testBean.increment}
</span>
<p:outputPanel id="static2">
Static : #{testBean.increment}
</p:outputPanel>
<p:outputPanel id="dynamic">
Dynamic : #{testBean.increment}
</p:outputPanel>
<p:poll interval="3" update="dynamic" />
</composite:implementation>
Use the component in a XHTML page:
<h:form id="myform">
<p:tabView id="tv1" >
<p:tab id="tab1" title="First Tab">
<comps:myComponent id="comp1" label="Abc" />
</p:tab>
<p:tab id="tab2" title="Second Tab">
<comps:myComponent id="comp2" label="Def" />
</p:tab>
</p:tabView>
</h:form>
And this is the code for the test bean:
#ManagedBean(name="testBean")
public class TestBean implements Serializable
{
static int _counter = 0;
public String getIncrement()
{
_counter++;
return Integer.toString(_counter);
}
}
I hope this example will be clear enough and close to what you want to get.
Please let me know.

How to get command link value(display name) from backing bean?

I have a p:commandLink in my xhtml with the value toggling between "Show"/"Hide".
Is there any way by which I can get the value of this commandlink from the backing bean?
I mean, I want to know what value the command link is showing currently i.e. Show/Hide?
To the point, the invoking component is just available in ActionEvent argument:
<h:commandLink id="show" value="Show it" actionListener="#{bean.toggle}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.toggle}" />
with
public void toggle(ActionEvent event) {
UIComponent component = event.getComponent();
String value = (String) component.getAttributes().get("value");
// ...
}
However, this is a poor design. Localizable text should absolutely not be used as part of business logic.
Rather, either hook on component ID:
String id = (String) component.getId();
or pass a method argument (EL 2.2 or JBoss EL required):
<h:commandLink id="show" value="Show it" actionListener="#{bean.toggle(true)}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.toggle(false)}" />
with
public void toggle(boolean show) {
this.show = show;
}
or even just call the setter method directly without the need for an additional action listener method:
<h:commandLink id="show" value="Show it" actionListener="#{bean.setShow(true)}" />
<h:commandLink id="hide" value="Hide it" actionListener="#{bean.setShow(false)}" />
As #BalusC suggested, your approach is not a good solution. But if you really want to do that, you can bind the component (p:commandLink) to your backingbean, as seen in What is the advantages of using binding attribute in JSF?.
After the component was bound, you can access the value attribute from the p:commandLink.

Grouping radio button inside data grid using primefaces 3.3 and jsf 2.0

I am new to jsf 2.0 and therefore i am facing a serious issue grouping the prime faces datagrid and radio buttons. I am using JSF 2.0-Primefaces 3.3, java 1.6, and running my application on tomcat server on windows operating system.
The issue is grouping data grid and radio button. The following paragraph will describe about an example code:
#ManagedBean(name="quickBill")
#ViewScoped
public class QuickBill extends BaseManagedBean implements Serializable {
private List<String[]> insurerIDs=null;
#PostConstruct
public void init(){
loadInsurer();
}
private void loadInsurer(){
logger.info("Entered Load Insurer");
insurerIDs = new ArrayList<String[]>();
if (null != insurerList) {
insurerIDs.add(new String[] {"InsurerID1","Insurer_Name1") });
insurerIDs.add(new String[] {"InsurerID2","Insurer_Name2") });
insurerIDs.add(new String[] {"InsurerID3","Insurer_Name3") });
insurerIDs.add(new String[] {"InsurerID4","Insurer_Name4") });
}
}
public List<String[]> getinsurerIDs() {
return insurerIDs;
}
}
The jsf code is as follows:
<p:dataGrid var="quickBillVar" value="#{quickBill.insurerIDs}" columns="4" >
<p:column selectionMode="single">
<p:selectOneRadio id="options" value="#{quickBill.selectedOption}">
<f:selectItem itemLabel="#{quickBillVar[1]}" itemValue="#{quickBillVar[1]}"/>
</p:selectOneRadio>
<p:commandLink id="insurerid" title="Isurer">
<p:graphicImage value="../../images/insurers1/#{quickBillVar[0]}.jpg"/>
</p:commandLink>
</p:column>
</p:dataGrid>
The above code when executed results in the display of the radio button, which allows user to select multiple radio button at the same time. However the requirement is to restrict user to select only one button rather than allowing user to select multiple button at a time. I have also used selectionMode="single" to produce the expected output but it didn't help much.
Kindly help me on this or provide me with examples which will overcome this issue.
I believe the custom layout in this example will help.
https://www.primefaces.org/showcase/ui/input/oneRadio.xhtml
You can try the below code using Map.
Backing bean code
String selectedInsurer;
Map<String,String> insurerIDs = new LinkedHashMap<String,String>();
insurerIDs.put("InsurerID1", "Insurer_Name1"); //(label, value)
insurerIDs.put("InsurerID2", "Insurer_Name2");
insurerIDs.put("InsurerID3", "Insurer_Name3");
insurerIDs.put("InsurerID4", "Insurer_Name4");
//-- getter & setter
At front end
<h:selectOneRadio value="#{quickBill.selectedInsurer}">
<f:selectItems value="#{quickBill.insurerIDs}" />
</h:selectOneRadio>

How to save a list/map/set in JSF with h:inputText + managed bean

What I'm trying to achieve is very similar to the one posted in the following link.
How to save an array in JSF with ui:repeat + h:inputText + managed bean?
I'm particularly fascinated with the answer provided by Arjan Tijms in the link above however what I want to achieve is slightly different. Consider the following code snippets.
The bean
import javax.annotation.PostConstruct;
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
#RequestScoped
#Named
public class MyBean {
List<String> choices;
public List<String> getChoices() {
return choices;
}
#PostConstruct
public void initChoices() {
choices= new ArrayList<String>();
}
public String save() {
// should save all the choices into some repository
return "";
}
}
and the facelet page
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:body>
<h:form>
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:commandButton value="Save" action="#{myBean.save}" />
</h:form>
</h:body>
</html>
The thing is, this will work if we have some initial data in the list at the beginning. What about situations where the initial list will be empty?
The ideal solution which I'm looking for is to have 1 h:inputText for each choice and when save button is clicked, all choices in each h:inputText is then added to the choices list. I've searched high and low but can't seem to find any hints on how this can be done.
If JSF 2 really doesn't support this, I guess I'll have to use the ugly way with just one h:inputText and use a converter to convert to and from a list but I'm still hoping that an ideal solution can be found.
Hopefully someone from stackoverflow can shed a light in the right direction for me.
Just add an "add" button which adds a new String to the list.
<ui:repeat value="#{myBean.choices}" varStatus="status">
<h:inputText value="#{myBean.choices[status.index]}" />
</ui:repeat>
<h:inputText value="#{myBean.newChoice}" />
<h:commandButton value="Add" action="#{myBean.add}" />
<h:commandButton value="Save" action="#{myBean.save}" />
with
private String newChoice;
public void add() {
choices.add(newChoice);
newChoice = null;
}
// ...
Note that this only works if bean is put in view scope. A request scoped one would be constructed on every request and hereby recreate the list everytime.

Resources