Referring composite component ID in f:ajax render - jsf

I am writing a composite component that is intended to wrap an input element, and augment it with an 'optional field' designation and h:message element below it.
Here is the component (in input.xhtml file):
<composite:interface/>
<composite:implementation>
<div>
#{component.children[1].setStyleClass(component.children[1].valid ? '' : 'inputError')}
<composite:insertChildren/>
</div>
<h:panelGroup styleClass="optional"
rendered="#{!component.parent.children[1].required}"
layout="block" >
#{msgs['common.optional.field']}
</h:panelGroup>
<h:message id="msgId"
for="#{component.parent.children[1].id}" errorClass="error"/>
</composite:implementation>
Again, the intended usage of the component is to wrap an h:input* element which is expected to be the first and immediate child of it in a using page.
In a using page I would then write:
<h:form id="f1">
<h:panelGrid border="0" columns="2" style="width: 80%">
<f:facet name="header">
<col width="40%" />
<col width="60%" />
</f:facet>
<h:outputLabel styleClass="sectionBody" for="i1"
value="Input 1"></h:outputLabel>
<my:input id="ii1">
<h:inputText id="i1" size="20" maxlength="20" tabindex="0"
required="true" label="Input 1">
</h:inputText>
</my:input>
<h:outputLabel styleClass="sectionBody" for="i2"
value="Input 2"></h:outputLabel>
<my:input id="ii2">
<h:inputText id="i2" size="20" maxlength="20" tabindex="0"
label="Input 2">
</h:inputText>
</my:input>
</h:panelGrid>
<br />
<h:commandButton value="Submit" tabindex="1">
<f:ajax listener="#{terminalImportBean.addTerminal}"
execute="#form" render="#form"/>
</h:commandButton>
</h:form>
This would work just fine using normal posts.
However if I add add f:ajax validation for "Input 1" (id="i1") and try to re-render the composite (ii1) using the following:
...
<h:outputLabel styleClass="sectionBody" for="i1"
value="Input 1"></h:outputLabel>
<my:input id="ii1">
<h:inputText id="i1" size="20" maxlength="20" tabindex="0"
required="true" label="Input 1">
<f:ajax listener="#{myBean.checkInput1}"
event="blur"
render="ii1"/>
</h:inputText>
</my:input>
...
I gen an error in the browser during ajax response processing:
malformedXML: During update: f1:ii1 not found
I tried using f1:ii1, :f1:ii1, but to no avail. When I use msgId or :f1:ii1:msgId it works. Does anybody know why?
I am using Mojarra 2.1.3
Thanks

That's because the composite component does by itself not render anything to the HTML. Only its children are been rendered to HTML. There does not exist any HTML element with ID f1:i11 in the generated HTML output. Open the page in browser, rightclick and View Source. Look in there yourself. There's no such element with that ID. JavaScript/Ajax is encountering exactly the same problem. It can't find the element in order to update it.
To solve this, you'd need to wrap the entire composite body in a HTML <div> or <span> and assign it an ID of #{cc.clientId} which basically prints UIComponent#getClientId().
<cc:implementation>
<div id="#{cc.clientId}">
...
</div>
</cc:implementation>
Then you can reference it as below:
<my:input id="foo" />
...
<f:ajax ... render="foo" />
You can even reference a specific composite component child.
<f:ajax ... render="foo:inputId" />
See also:
Is it possible to update non-JSF components (plain HTML) with JSF ajax?
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

Related

SelectBooleanCheckbox receives focus without mouseover

I have a weird problem with jsf components (h:inputFile & h:selectBooleanCheckbox).
Both components receive focus, even when my mouse is somewhere else on the page. Here is the code:
<h:form id="logoUpload" enctype="multipart/form-data">
<div>
<h:outputLabel rendered="true">
<h:inputFile id="companyLogo" label="file" value="#{fileHandlerBean.part}" >
<f:validator validatorId="FileUploadValidator" />
</h:inputFile>
</h:outputLabel>
</div>
<div class="clear" />
<h:outputLabel rendered="true">
<div>
<div style="width: 5%">
<h:selectBooleanCheckbox id="acceptToULogo" value="#{companyEditController.confirmToU}">
<p:ajax event="change" update="buttonLogo" />
</h:selectBooleanCheckbox>
</div>
<div style="width: 95%">
<h:outputText value="Some Text " />
</div>
<br />
<h:commandButton id="buttonLogo" styleClass="formbutton" value="Upload"
action="#{companyEditController.companyLogoUpload()}"
actionListener="#{fileHandlerBean.uploadCompanyLogo()}"
disabled="#{!companyEditController.confirmToU}"/>
</div>
</h:outputLabel>
</h:form>
If I move the mouse over the h:outputText the checkbox receives focus.
I had the same problem with the h:inputFile tag. I solved it by surrounding it with a h:outputLabel tag, but unfortunately it doesn´t workd with the selectBooleanCheckbox.
Did somebody have the same problem in the past and knows a solution?
This is because everything is wrapped in the h:outputLabel tag. This outputLable is rendered as a plain label html element.
You can see form the W3C specification that anything inside the label will toggle the control
The element does not render as anything special for the user. However, it provides a usability improvement for mouse users, because if the user clicks on the text within the element, it toggles the control
To fix this, you need to replace the h:output label tag using a h:panelGroup layout="block" which renders a <div>:
<h:panelGroup layout="block" rendered="true">
<div>
<div style="width: 5%">
<h:selectBooleanCheckbox id="acceptToULogo" >
<p:ajax event="change" update="buttonLogo" />
</h:selectBooleanCheckbox>
</div>
<div style="width: 95%">
<h:outputText value="Some Text " />
</div>
<br />
<h:commandButton id="buttonLogo" styleClass="formbutton" value="Upload"/>
</div>
</h:panelGroup>

Customize attribute of one panel id of Composite component .in JSF2,2 [duplicate]

I am writing a composite component that is intended to wrap an input element, and augment it with an 'optional field' designation and h:message element below it.
Here is the component (in input.xhtml file):
<composite:interface/>
<composite:implementation>
<div>
#{component.children[1].setStyleClass(component.children[1].valid ? '' : 'inputError')}
<composite:insertChildren/>
</div>
<h:panelGroup styleClass="optional"
rendered="#{!component.parent.children[1].required}"
layout="block" >
#{msgs['common.optional.field']}
</h:panelGroup>
<h:message id="msgId"
for="#{component.parent.children[1].id}" errorClass="error"/>
</composite:implementation>
Again, the intended usage of the component is to wrap an h:input* element which is expected to be the first and immediate child of it in a using page.
In a using page I would then write:
<h:form id="f1">
<h:panelGrid border="0" columns="2" style="width: 80%">
<f:facet name="header">
<col width="40%" />
<col width="60%" />
</f:facet>
<h:outputLabel styleClass="sectionBody" for="i1"
value="Input 1"></h:outputLabel>
<my:input id="ii1">
<h:inputText id="i1" size="20" maxlength="20" tabindex="0"
required="true" label="Input 1">
</h:inputText>
</my:input>
<h:outputLabel styleClass="sectionBody" for="i2"
value="Input 2"></h:outputLabel>
<my:input id="ii2">
<h:inputText id="i2" size="20" maxlength="20" tabindex="0"
label="Input 2">
</h:inputText>
</my:input>
</h:panelGrid>
<br />
<h:commandButton value="Submit" tabindex="1">
<f:ajax listener="#{terminalImportBean.addTerminal}"
execute="#form" render="#form"/>
</h:commandButton>
</h:form>
This would work just fine using normal posts.
However if I add add f:ajax validation for "Input 1" (id="i1") and try to re-render the composite (ii1) using the following:
...
<h:outputLabel styleClass="sectionBody" for="i1"
value="Input 1"></h:outputLabel>
<my:input id="ii1">
<h:inputText id="i1" size="20" maxlength="20" tabindex="0"
required="true" label="Input 1">
<f:ajax listener="#{myBean.checkInput1}"
event="blur"
render="ii1"/>
</h:inputText>
</my:input>
...
I gen an error in the browser during ajax response processing:
malformedXML: During update: f1:ii1 not found
I tried using f1:ii1, :f1:ii1, but to no avail. When I use msgId or :f1:ii1:msgId it works. Does anybody know why?
I am using Mojarra 2.1.3
Thanks
That's because the composite component does by itself not render anything to the HTML. Only its children are been rendered to HTML. There does not exist any HTML element with ID f1:i11 in the generated HTML output. Open the page in browser, rightclick and View Source. Look in there yourself. There's no such element with that ID. JavaScript/Ajax is encountering exactly the same problem. It can't find the element in order to update it.
To solve this, you'd need to wrap the entire composite body in a HTML <div> or <span> and assign it an ID of #{cc.clientId} which basically prints UIComponent#getClientId().
<cc:implementation>
<div id="#{cc.clientId}">
...
</div>
</cc:implementation>
Then you can reference it as below:
<my:input id="foo" />
...
<f:ajax ... render="foo" />
You can even reference a specific composite component child.
<f:ajax ... render="foo:inputId" />
See also:
Is it possible to update non-JSF components (plain HTML) with JSF ajax?
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"

p:outputPanel does not render page sections

I have two p:ouputPanels which have the rendered attribute. They should be rendered when the value of the underlying getter/setter changes. However, the underlying values change in the right order. The first panel disappears, However the second panel does not show up. Even NOT in the HTML code!
My two panels:
<p:outputPanel id="PanelParent">
<h:form>
<p:outputPanel id="PanelForm" rendered="#{PageService.isVisibilityForm()}">
<h:commandButton value="Button"
action="#{PageService.persist}"
styleClass="btn btn-primary opal_btn submit_form_new" />
</h:form>
</p:outputPanel>
<p:outputPanel id="PanelMessage" rendered="#{PageService.isVisibilityMessage()}">
//Message
</p:outputPanel>
</p:outputPanel>
I appreciate your answer!!!
-UPDATE-
In the code, I reference to the persist method and in this method I change the getter and setter of the visibility for each section.
-UPDATE1-
OK here is in fact my code:
<p:outputPanel id="parentPanel">
<p:outputPanel id="PanelForm"
rendered="#{PageService.isVisibilityForm()}">
<div>
<div>
<h:form class="homepage_invitee_form" action="" method="POST">
<p:messages id="messages" showDetail="false" autoUpdate="true"
closable="true" />
<h:inputText required="true"
value="#{PageService.instance.name}"
name="name" placeholder="Last Name"
styleClass="lastname_new" id="lastname_new"
type="text placeholder" />
<h:commandButton value="Press"
action="#{PageService.persist()}"/>
<f:ajax render="" />
</h:commandButton>
</h:form>
</div>
</div>
</p:outputPanel>
<p:outputPanel id="PanelThank"
rendered="#{PageService.isVisibilityThank()}">
<div>
Message
</div>
</p:outputPanel>
</p:outputPanel>
I really do not see where it fails? ;(
It's like Xtreme Biker said <f:ajax> render attribute will render elements that are already present in the DOM. In your case, <p:outputPanel id="PanelThank"> render attribute was evaluating to false so it was not in the DOM. Therefore, <f:ajax> could not render it. You need to point to something that is always visible. Change
<f:ajax render="" />
to
<f:ajax render=":PanelThank" />
but more importantly change
<p:outputPanel id="PanelThank" rendered="#{PageService.isVisibilityThank()}">
<div>
Message
</div>
</p:outputPanel>
to
<p:outputPanel id="PanelThank">
<p:outputPanel rendered="#{PageService.isVisibilityThank()}">
<div>
Message
</div>
</p:outputPanel>
</p:outputPanel>
Consider refactoring your code also. For instance, action and method in <h:form> is not needed.
rendered attribute defines if JSF will render your component in the DOM tree. Your problem is you cannot update a component which is not in the tree because you simply don't have it:
<p:outputPanel id="PanelForm" rendered="#{PageService.isVisibilityForm()}">
//my Form
<p:outputPanel>
<!--Fails if not PageService.isVisibilityForm(), because you don't have the component itself in the tree! So can't find it-->
<p:ajax update="PanelForm"/>
Your best is to wrap your content in another container which is always rendered and update it instead of the other one:
<h:panelGroup id="updatablePanel">
<p:outputPanel rendered="#{PageService.isVisibilityForm()}">
//my Form
<p:outputPanel>
</h:panelGroup>
<p:ajax update="updatablePanel"/>

Can EL value pass one to another in JSF and Facelets?

I would like to pass the EL one JSF page to Facelets template. Facelets template just understand EL value as string value. How can I pass EL String to Faceltes Template?
page1.xthml
<ui:include ..../>
<ui:param actionBeanMethod="#{EmployeeActionBean.deleteEmplayee(emp)}>
page2.xthml
<ui:include ..../>
<ui:param actionBeanMethod="#{DepartmentActionBean.deleteDepartment(dep)}>
In comfirmationTemplate.xml
<a4j:commandLink onclick="#{rich:component('confirmation')}.show();return false">
<h:graphicImage value="/img/delete.png" />
</a4j:commandLink>
<a4j:jsFunction name="submit" action="#{actionBeanMethod}"/>
<rich:popupPanel id="confirmation" width="250" height="150">
<f:facet name="header">Confirmation</f:facet>
<h:panelGrid>
<h:panelGrid columns="2">
<h:graphicImage value="/img/alert.png" />
<h:outputText value="Are you sure?" style="FONT-SIZE: large;" />
</h:panelGrid>
<h:panelGroup>
<input type="button" value="OK" onclick="#{rich:component('confirmation')}.hide();submit();return false" />
<input type="button" value="Cancel" onclick="#{rich:component('confirmation')}.hide();return false" />
</h:panelGroup>
</h:panelGrid>
</rich:popupPanel>
I would like to change action of a4j:jsFuction dynamically.
When page1.xhtm is call,
<a4j:jsFunction name="submit" action="#{EmployeeActionBean.deleteEmplayee(emp)"/>
When page2.xhtm is call,
<a4j:jsFunction name="submit" action="#{DepartmentActionBean.deleteDepartment(dep)"/>
Can it possible?
You can't pass method expressions as <ui:param> value. It accepts only value expressions.
You basically need to create a custom taghandler which re-interprets the value expression as a method expression. From the current open source JSF component/utility libraries, the OmniFaces <o:methodParam> is the only one which does exactly that.
<o:methodParam name="methodParam" value="#{actionBeanMethod}" />
<a4j:jsFunction name="submit" action="#{methodParam}" />
You only need to register the Facelets include as a Facelets tag file and use it as
<my:confirmationTemplate actionBeanMethod="#{EmployeeActionBean.deleteEmplayee(emp)}" />
An alternative is to use a composite component instead.

Error "<f:ajax> contains an unknown id" when used to render <rich:message>

This is my form:
<h:body>
<h:form>
<h:panelGrid columns="3" >
<h:outputLabel for="name" value="Primeiro nome:" />
<h:inputText id="name" value="#{register.person.name}" >
<f:ajax event="blur" render="m_name" listener="#{register.validateName}" />
</h:inputText>
<rich:message id="m_name" for="name" />
//.. others fields
</h:panelGrid>
</h:form>
</body>
When i try to execute on Glassfish gives the follow error :
javax.servlet.ServletException: <f:ajax> contains an unknown id 'm_name' - cannot locate it in the context of the component name
But if i change <rich:message ..> by <h:message..> it works (I want it works with rich:message because it returns an image and a message )
Why this is happening ? Never happened with me before, until now.
The RichFaces component reference tells this about the <rich:messages>:
13.1.1. Basic usage
...
The <rich:message> component is automatically rendered after an Ajax request. This occurs without the use of an component or a specific reference through the render attribute of the Ajax request source.
So, I'd just remove the render attribute on m_name and replace <f:ajax> by <a4j:ajax>.
<h:inputText id="name" value="#{register.person.name}" >
<a4j:ajax event="blur" listener="#{register.validateName}" />
</h:inputText>
<rich:message id="m_name" for="name" />
If you want to explicitly specify it anyway, you can set ajaxRendered="false" on the <rich:message> component.
<h:inputText id="name" value="#{register.person.name}" >
<f:ajax event="blur" listener="#{register.validateName}" render="m_name" />
</h:inputText>
<rich:message id="m_name" for="name" ajaxRendered="false" />
Looks like a richfaces behavior to me. I suspect you will have to file a bug report.
A work-around is to enclose the rich:message tag inside a rich:message tag inside a div tag, then give the div tag an id="m_name".

Resources