f:param is not working with h:graphicImage - jsf-2

I'm getting <f:param> i.e., menuItemIndex value as null during my ajax call. Is it because it is with in <h:graphicImage> ??? Can any one suggest please? Note: Parameter is getting passed if I use <h:commandLink> instead of <h:graphicImage>.
<c:forEach items="#{cc.attrs.value}" var="menuItem" varStatus="loopItem">
....
<ui:fragment rendered="#{menuItem.hasChildren}">
<h:graphicImage library="images" name="#{menuItem.symbol}">
<f:ajax render=":fatcaForm:myMenu:menuID" event="click" listener="#{menuBean.refreshMenu}" />
<f:param name="menuItemIndex" value="{loopItem.count}" />
</h:graphicImage>
</ui:fragment>
....
</c:forEach>

The <h:graphicImage> is not a command component and it does therefore not support <f:param> children at all. The <f:param> works only when nested in an UICommand component, such as <h:commandLink> as you found out yourself.
So, this should do:
<h:commandLink action="#{menuBean.refreshMenu}">
<h:graphicImage library="images" name="#{menuItem.symbol}" />
<f:ajax render=":fatcaForm:myMenu:menuID" />
<f:param name="menuItemIndex" value="#{loopItem.count}" />
</h:commandLink>
(note that I fixed the EL syntax error in the <f:param value> as well)
Unrelated to the concrete problem, how you used the <h:graphicImage library> is not entirely right. Please carefully read What is the JSF resource library for and how should it be used?

Related

How to use generated ids in EL (jsf, composite)?

I want to have a composite that composes
<h:form id="f_imgA" >
<h:graphicImage id="imgA"
onclick="document.getElementById('#{k_imgA.clientId}').value=mods(event)"
value="images/img?r=#{Math.random()}">
<f:ajax event="click" listener="#{mBean.handleEvent}"
execute="#this k_imgA" render="#this"></f:ajax>
</h:graphicImage>
<h:inputHidden id="k_imgA" binding="#{k_imgA}" value="#{mBean.keyX}" />
</h:form>
when I write
<comps:cimg imgId="imgA" />
The original purpose of this code is to send the modifier-states (Ctrl, Shift, Alt) to the server.
I have
<composite:interface>
<composite:attribute name="imgId" />
</composite:interface>
<composite:implementation>
<h:form id="f_#{cc.attrs.imgId}">
<h:graphicImage id="#{cc.attrs.imgId}"
onclick="document.getElementById('#{k_${cc.attrs.imgId}.clientId}').value=mods(event)"
value="images/img?r=#{Math.random()}">
<f:ajax event="click" execute="#this k_#{cc.attrs.imgId}"
listener="#{mBean.handleEvent}" render="#this">
</f:ajax>
</h:graphicImage>
<h:inputHidden id="k_#{cc.attrs.imgId}"
binding="k_#{cc.attrs.imgId}" value="#{mBean.keyX}" />
</h:form>
</composite:implementation>
which, quite expected, does not work. The offending expression is
#{k_${cc.attrs.imgId}.clientId}
which is intended to return the clientId of the hiddenInput with id k_imgA . As far as I know, EL cannot handle nested expressions like the one above, but it was worth a try. So is there a simple, straightforward way to get the clientId of k_imgA? I don't want to use more javascript, if this can be avoided.
Edit:
don't get confused about #{Math.random()}, it works just because I have a bean called "Math".
The javascript function mods is given by
<h:outputScript target="body">function mods(event) {return ((event.ctrlKey)?1:0)+((event.shiftKey)?2:0)+((event.altKey)?4:0)} </h:outputScript>
You don't need to fiddle with all those _#{cc.attrs.imgId}. Just give the composite a fixed id. They are already naming containers themselves. JSF will then worry about the rest.
<composite:implementation>
<h:form id="f">
<h:graphicImage id="i" ... />
<h:inputHidden id="k" ... />
</h:form>
</composite:implementation>
Usage:
<comps:cimg id="imgA" />
Generated HTML:
<form id="imgA:f" ...>
<img id="imgA:f:i" ... />
<input id="imgA:f:k" ... />
</form>
As to the JS attempt, you'd best use element's own ID as base:
<h:graphicImage onclick="document.getElementById(id.substring(0,id.lastIndexOf(':')+1)+'k').value='...'" />
Or, easier, if the hidden element is guaranteed to be the direct sibling of the image element in the generated HTML DOM tree, then just grab it by Node#nextSibling:
<h:graphicImage onclick="nextSibling.value='...'" />
<h:inputHidden ... />
The binding will never work as in your attempted construct, and even then you'd best do it via a Map in request scope or a so-called backing component.
See also:
Accessing JSF nested composite component elements in JavaScript
Integrate JavaScript in JSF composite component, the clean way
Rerendering composite component by ajax

JSF 2.2 custom validator not triggered in ui:repeat

after a desperate period of trials and errors i come to you looking for help, since now i am even unsure if i am doing it all wrong.
My code below displays some fields from a user profile in read only input text boxes. The data comes from a bean as ArrayList of "field" objects, whos properties are described in the ui:param directives.
The user can click an unlock/lock button next to the box to start/finish editing her data.
I want to trigger input validation when the user presses enter after editing or clicks the lock button.
But whatever i tried, after editing and pressing enter or clicking the button, the changed value is not written back and my custom validator is not triggered. Somehow it seems that after clicking the button the then rendered input box is not bound to the field? However, the validator works (and all attributes get passed to it) if used in an input text that is always rendered - and i don't understand it :)
Please have a look at it. If i did not explain my intent well enough or if you need more code, please let me know.
Edit: the annotations of the backing bean:
#ManagedBean( name = "beanProfile" )
#RequestScoped
The jsf code:
<ui:composition>
<ui:param name="i18n" value="#{field.i18n}" />
<ui:param name="val" value="#{field.value}" />
<ui:param name="req" value="#{field.required}" />
<ui:param name="min" value="#{field.min}" />
<ui:param name="max" value="#{field.max}" />
<ui:param name="validationType" value="#{field.validationType}" />
<ui:param name="useHidden" value="#{field.hidden}" />
<ui:param name="locked" value="#{field.locked}" />
<ui:param name="fullName" value="#{beanProfile.name}" />
<h:form id="profileFrm">
<h:outputText value="#{msg.role_profile} " styleClass="headingOutputText" />
<h:outputText value="#{fullName}" styleClass="headerTitle" />
<p />
<h:panelGroup>
<ui:repeat var="field" value="#{beanProfile.userFields}">
<h:panelGrid columns="2">
<h:outputText value="#{msg[i18n]}" styleClass="headerTitle" />
<h:message showDetail="true" for="visInput" styleClass="warn"
rendered="#{!useHidden}" />
<h:message showDetail="true" for="invisInput" styleClass="warn"
rendered="#{useHidden}" />
</h:panelGrid>
<h:panelGrid columns="2" columnClasses="nameColumn">
<h:inputText id="visInput" required="true" value="#{val}"
rendered="#{!useHidden}" readonly="#{locked}" >
<f:validator validatorId="customValidator" />
<f:attribute name="requiredField" value="#{req}" />
<f:attribute name="minLen" value="#{min}" />
<f:attribute name="maxLen" value="#{max}" />
<f:attribute name="type" value="#{validationType}" />
</h:inputText>
<h:inputSecret id="invisInput" required="true" value="#{val}"
rendered="#{useHidden}" readonly="#{locked}">
<f:validator validatorId="customValidator" />
<f:attribute name="requiredField" value="#{req}" />
<f:attribute name="minLen" value="#{min}" />
<f:attribute name="maxLen" value="#{max}" />
<f:attribute name="type" value="#{validationType}" />
</h:inputSecret>
<h:commandLink id="lock" action="#{beanProfile.lock(field)}"
rendered="#{!locked}" title="#{msg.profile_lock}">
<h:graphicImage height="16" width="16"
name="images/padlock_unlocked.svg" alt="#{msg.profile_lock}" />
</h:commandLink>
<h:commandLink id="unlock" action="#{beanProfile.unlock(field)}"
rendered="#{locked}" title="#{msg.profile_unlock}">
<h:graphicImage height="16" width="16"
name="images/padlock_locked.svg" alt="#{msg.profile_unlock}" />
</h:commandLink>
</h:panelGrid>
</ui:repeat>
</h:panelGroup>
<p />
<h:commandButton id="submitProfileBtn" value="#{msg.cmd_submit}"
styleClass="button" includeViewParams="true"
action="#{beanProfile.submitProfile()}" />
</h:form>
</ui:composition>
The origin of your problem is that you are using the RequestScoped scope for your backing bean containing the Model, so when you want to do a postback request in order to execute the backing bean method the binding just have dissapeared (not in the server memory) and the JSF lifecycle doesn't execute as expected. The solution is to use a longer scope as the ViewScoped scope. Ideally you should use the CDI compatible viewScoped scope, so you have to use JSF 2.2.x version.
Thank you lametaweb, you led me in the right direction.
Being unable to use the #ViewScoped annotation i found the link
how-to-install-cdi-in-tomcat
and followed BalusC's directions for using CDI in Tomcat. Then i had to let all the java classes implement the Serializable interface.
Now i can use the #ViewScoped annotation and the validator gets triggered.

actionListener not called inside <c:if>

I have the following code, Using jsf2.2, primefaces 3.2.
My requirement is to update the Project depending on the updateFlag.
when i use c:if (xmlns:c="http://java.sun.com/jsp/jstl/core") like the following code the action Listener for the Update commandButton is not called. but if i use < p:panel rendered="#{projectBean.updateFlag}" > instead of < c:if > it works. Please help i dint get it, i think i should use c:if but its not working.
<p:dialog widgetVar="projectUpdate" id="projectUpdatePanel" modal="false" >
<p:panel>
<c:if test="#{projectBean.updateFlag == false}">
<h:outputText value="Project Title" />
<p:inputText disabled="true" value="#{projectBean.selectedProjectDo.projectTitle}" />
<p:commandButton value="Update" disabled="true" />
<p:commandButton value="Cancel" actionListener="#{projectBean.cancelUpdate}" />
</c:if>
<c:if test="#{projectBean.updateFlag == true}">
<h:outputText value="Project Title"/>
<p:inputText value="#{projectBean.selectedProjectDo.projectTitle}" />
<p:commandButton value="Update" actionListener="#{projectBean.updateProject}" />
<p:commandButton value="Cancel" actionListener="#{projectBean.cancelUpdate}" />
</c:if>
</p:panel>
</p:dialog>
You better just use it the following way (put a condition on the disabled attribute)
<p:panel>
<h:outputText value="Project Title"/>
<p:inputText disabled="#{not projectBean.updateFlag}"
value="#{projectBean.selectedProjectDo.projectTitle}" />
<p:commandButton disabled="#{not projectBean.updateFlag}" value="Update"
actionListener="#{projectBean.updateProject}" />
<p:commandButton value="Cancel" actionListener="#{projectBean.cancelUpdate}" />
</p:panel>
In general : don't use JSTL tags unless you really need them...
This is a classic example of non-DRY code, which is bad. Daniel shows perfectly how to make it DRY, however he didn't explain the cause of your problem.
Based on the problem symptoms, this will happen when #{projectBean} is a view scoped bean. View scoped beans are stored in the JSF view state. So, view scoped beans are only available after restore view phase. However, JSTL tags runs during restore view phase, while the view scoped beans are not available yet. This causes creation of a brand new view scoped bean instance, which is then later replaced by the real view scoped bean which was stored in the restored JSF view state. The brand new and separate view scoped bean which is used by JSTL will have all its properties set to default and thus the block which has updateFlag=false will always be invoked.
See also:
JSTL in JSF2 Facelets... makes sense?

f:ajax doesn't work when parameters are passed using f:param

I am calling a method on the click of link. The following code works ajaxfully
<ui:repeat value="#{myBean.names}" var="name"
varStatus="idx">
<li>
<h:commandLink value="#{name.label}">
<f:ajax execute="#this" event="click" render="#all" listener="#{myBean.changeActiveName}" >
</f:ajax>
</h:commandLink>
</li>
</ui:repeat>
But when I try to pass parameter to the Ajax call it starts refreshing the whole page
<ui:repeat value="#{myBean.names}" var="name"
varStatus="idx">
<li>
<h:commandLink value="#{name.label}">
<f:ajax execute="#this" event="click" render="#all" listener="#{myBean.changeActiveName}" >
<f:param name="idx" value="#{idx}" />
</f:ajax>
</h:commandLink>
</li>
</ui:repeat>
What is wrong with this code?
The <f:param> has to be a child of the parent UICommand component, not of <f:ajax>.
<h:commandLink value="#{name.label}">
<f:param name="idx" value="#{idx}" />
<f:ajax listener="#{myBean.changeActiveName}" render="#all" />
</h:commandLink>
(note that I removed the execute and event attributes as your definitions are the defaults already; plus I wonder how it's useful to send a whole IterationStatus instance as request parameter ... maybe you just wanted to send the index instead? Use #{idx.index} instead or so)
See also:
How can I pass selected row to commandLink inside dataTable? (although this treats <h:dataTable>, exactly the same answer applies to <ui:repeat> as well)

f:ajax within ui:repeat, unknown id for the component [duplicate]

This question already has answers here:
How to find out client ID of component for ajax update/render? Cannot find component with expression "foo" referenced from "bar"
(6 answers)
Closed 7 years ago.
When I try to render a panelGroup by an ajax call, it gives unknown id.
<h:form id="form1" prependId=false>
<h:panelGroup id="panel1">
<h:dataTable/>
<ui:repeat value="#{bean.page}" var="page">
<h:commandLink value="#{page}">
<f:ajax execute="#form" render="panel1" listener="#{bean.page}" />
</h:commandLink>
</ui:repeat>
</h:panelGroup>
</h:form>
When I tried this code, it gives unknown id panel1. I tried with id ":panel1" too. I get the same error.
A relative client ID (i.e. not starting with :) is relative to the current parent NamingContainer component. The <ui:repeat> is also a NamingContainer. So the render="panel1" is looking for the component within the context of <ui:repeat>. This isn't going to work. An absolute client ID (i.e. starting with :) is looking for the component within the context of view root. But you've it inside a <h:form> -which is in turn another NamingContainer component-, so the render=":panel" is also not going to work.
The following should work, with prependId="false" removed so that you can refer it:
<h:form id="form1">
<h:panelGroup id="panel1">
<h:dataTable/>
<ui:repeat value="#{bean.page}" var="page">
<h:commandLink value="#{page}">
<f:ajax execute="#form" render=":form1:panel1" listener="#{bean.page}" />
</h:commandLink>
</ui:repeat>
</h:panelGroup>
</h:form>
By the way, if you actually want to render only the table, then you should be doing this:
<h:form id="form1">
<h:panelGroup>
<h:dataTable id="table1" />
<ui:repeat value="#{bean.page}" var="page">
<h:commandLink value="#{page}">
<f:ajax execute="#form" render=":form1:table1" listener="#{bean.page}" />
</h:commandLink>
</ui:repeat>
</h:panelGroup>
</h:form>
Update: as per the comments, it turns out that you have changed the JSF default NamingContainer separator character from : to _ by configuration. In that case, you need to use _ instead of : in the client ID selector.
<f:ajax execute="#form" render="_form1_panel1" listener="#{bean.page}" />
<ui:repeat value="#{interaction.interactionListBean}" var="interactionItr">
<h:commandLink value="#{interactionItr.interactionDate}" styleClass="#{interaction.createImage}" style="margin:0 5px 5px 0!important; display:inline-block;"><br/>
<f:ajax render=":formId:interactionDate :formId:category :formId:activity :formId:status :formId:channel :formId:status1 :formId:caseId :formId:comment :formId:user1 :formId:team :formId:user :formId:transit "
listener="#{interactionController.interactionDetailGet}"/>
<f:param name="RefId" value="#{interaction.interactionRefId}"/>
</h:commandLink>
</ui:repeat>
problem :
please refer above with above code their is no exception on console but the ajax listerner will not invoke when I saw this post similiar kind of concept being use just I was place the exceute="#form" then my coding is working fine
solution:
execute="#form"

Resources