JSF - Two Questions about actions on UIComponent - jsf

So, let me show us my troubles :)
1 - When i click on a commandbutton
<h:commandButton value="Somethings">
<f:setPropertyActionListener target="#{bean.method}" value="some" />
<f:ajax render="rendering"/>
</h:commandButton>
I dont do any action to the commandButton. Just i fire the ajax call. If i add an action on the button (like action="bean.myAction) it will be executedat the 5° phase of the JSF lifecycle (allright, only if i write event="action" in the f:ajax, but thats as default). Right? But the f:ajax is fired by cliccing on the button as default? Because for a ListBox for example, it's fired only if i write event="change" (the same, i shouldnt write it, because is as default).
2 - When i click on image
<h:graphicImage value="img/img.png" alt="img">
<f:setPropertyActionListener target="#{bean.method}" value="some" />
<f:ajax event="onclick" render="rendering"/>
</h:graphicImage>
This doesnt work. Why?
As usual, thanks for the help!!!!

1 - When i click on a commandbutton
I dont do any action to the commandButton. Just i fire the ajax call. If i add an action on the button (like action="bean.myAction) it will be executedat the 5° phase of the JSF lifecycle
The f:setPropertyActionListener will be executed in the 5th phase as well.
(allright, only if i write event="action" in the f:ajax, but thats as default). Right? But the f:ajax is fired by cliccing on the button as default? Because for a ListBox for example, it's fired only if i write event="change" (the same, i shouldnt write it, because is as default).
The f:ajax just changes the behaviour from a synchronous submit to asynchronous (partial) submit. It does that by generating some additional JavaScript code to the desired event attribute of the parent component (e.g. onclick, onchange, etc, look in generated HTML output in webbrowser). It doesn't change anything in the JSF lifecycle. Only the rendered response will be a partial response which is exactly the part which is to be updated in the component(s) with ID as definied in render attribute.
2 - When i click on image
This doesnt work. Why?
Because the h:graphicImage does not support f:setPropertyActionListener at all. It only works in UICommand components.
You want to wrap it in a h:commandLink instead.
<h:commandLink>
<f:setPropertyActionListener target="#{bean.method}" value="some" />
<f:ajax event="action" render="rendering"/>
<h:graphicImage value="img/img.png" alt="img"/>
</h:commandLink>
(and if necessary style the border/underline caused by generated <a> element away with CSS)

Related

ui:repeat with a list sending right object to a p:dialog

I currently have a giant ui:repeat. Within this ui:repeat, some of the repeated objects have a url to a popup image associated with them. When someone clicks display under that particular object, I need the url to popup in a p:dialog.
<ui:repeat var="thing" value="#{bean.thingList}">
<p:commandLink value="details" onclick="miniImage.show();"
update=":#{p:component('chart')}"
action="#{bean.setCurrentImg(thing.imageUrl)}"
rendered="#{thing.includeImage}">
</p:commandLink>
</ui:repeat>
and at the bottom of the page:
<p:dialog id="chart" widgetVar="miniImage" >
<h:graphicImage value="#{bean.currentImg}"/>
</p:dialog>
And in the backing bean I tried using a simple setter and getter for currentImg.
I am a bit confused on this now and would like to accomplish this without having to submit the entire form as well. Any help is greatly appreciated.
If you're using PrimeFaces 3.3 or newer, you could just add partialSubmit="true" to the command component. You can then control the to-be-processed components in process attribute. In this particular case, just the current component (the command component itself) is sufficient, thus so process="#this":
<p:commandLink ... process="#this" partialSubmit="true" />
This way only the request parameters which are really necessary for the process will be sent.
Unrelated to the concrete problem, I suggest to use oncomplete instead of onclick to open the dialog. Otherwise the dialog is opened before update takes place and may cause poor user experience as the enduser would see the image instantly changing.

PrimeFaces dialog validation errors

What i want to do is like basic row selection example at Primefaces showcase(http://www.primefaces.org/showcase/ui/datatableRowSelectionByColumn.jsf) I want to update my datatable's row. The problem is when i click to update button at datatable, dialogbox appears with validation errors.
Second thing is what is the order of method execution times.(action-update-onclick-f:setPropertyActionListener)
<p:commandButton id="updateButtonId"
action="#{myController.showCompanyEditPanel}"
update=":tabView:companyForm:companyEditPanel"
onclick="companyDialog.show()"
icon="ui-icon-pencil" title="update">
<f:setPropertyActionListener value="#{company}" target="#{myController.selectedCompany}" />
</p:commandButton>
<p:dialog id="editCompanyDialogId" header="CompanyEdit" widgetVar="companyDialog" resizable="false">
<p:panel id="companyEditPanel" >
//some stuff here
</p:panel>
</p:dialog>
You seem to be missing a major point of using a <p:commandButton> here, as well as seem to be mixing client-side and server-side events.
First on <p:commandButton>. This component is designed to POST (partial) form data to the current URL, do business job in action(listener) method and return updated components / perform navigation. You can of course 'attach' JavaScript events to all those attributes.
Second, onclick, oncomplete, and other on... attribute are corresponding to some client-side events. In particular, onclick function is triggered when button was clicked, oncomplete function is called when DOM was updated after the AJAX call, i.e. the elements specified in <p:ajax update="..."> or simply in update="..." attribute of <p:commandButton>.
Third, all action listeners (thus, actionListener attribute, <f:actionListener> tag, <f:setPropertyActionListener> tag) will be executed right in the order they are specified in your tag, see this answer for more elaboration. The last one to be executed is action method, after which response is sent back.

Why does a h:commandButton fail to submit the form if it's parent is dynamically rendered?

This JSF1 code has me totally puzzled for hours. The basic setup is this page displayed with Seam2:
<h:form encType="multipart/form-data">
<rich:dataTable value="#{results}">
...
</rich:dataTable>
<h:selectOneMenu value="#{contact.type}">
<s:selectItems value="#{contactTypes}" var="t" label="#{t.label}" />
<s:convertEntity />
<a4j:support event="onchange" reRender="submitControls" />
</h:selectOneMenu>
<h:selectOneMenu value="#{template}">
<s:selectItems value="#{allTemplates}" var="t" label="#{t.label}" />
<s:convertEntity />
<a4j:support event="onchange" reRender="submitControls" />
</h:selectOneMenu>
<a4j:outputPanel id="submitControls" layout="block">
<a4j:outputPanel rendered="#{null != results and results.size gt 0 and ('ONE' == contact.type.label or template != null)}">
<h:commandButton value="submit" action="#{manager.generate}" />
</a4j:outputPanel>
<h:outputText value="Search first" rendered="#{results == null or results.size == 0}" />
<h:outputText value="Select template first" rendered="#{'ONE' == contact.type.label and template == null}" />
</a4j:outputPanel>
</h:form>
Obviously, the original page is a bit larger. What has me scratching my head is that if I don't change contact.type (leave it at a default selected by the backing bean) the form submits fine. If I switch the type to ONE this correctly renders the "Select template first" text instead of the submit control. Restoring the submit button by selecting another type re-produces the <input> BUT without the onclick handler that was there when the form was first rendered.
Now a click on the <h:commandButton> sends a request to the server but does NOT trigger the associated action. However, it now restores the onclick handler and a second click triggers a proper submit.
I'm at a loss why this is so. Any suggestions?
EDIT: moving the rendered attribute to the button results in the same behavior (even if it did work, the original panels contain more controls that share the same condition, so they do serve a purpose)
EDIT2: I've just tested that simply re-adding the "lost" onclick handler (via firebug) that gets rendered on the submit button makes the action work as intended. I'm beginning to suspect a bad interaction between richfaces and the trinidad libs also included in this project (but not used on this page).
It's a safeguard against tampered/hacked requests. Otherwise a hacker would be able to invoke actions s/he isn't allowed to invoke by just editing the sent HTTP request parameters accordingly that the non-rendered (e.g. due to missing "ADMIN" role) command button will be invoked.
You need to make sure that you prepare the same model (managed bean instance with all properties responsible holding the conditions behind rendered attribute) during the HTTP request of processing the form submit as it was during the HTTP request of displaying the form. In JSF2, this is easy achievable by placing the bean in the view scope instead of the request scope. The view scope lives as long as you're interacting with the same view. In JSF1, you'd need to grab a 3rd party framework tag like Tomahawk's <t:saveState> or RichFaces' <a4j:keepAlive> in order to simulate the JSF2 view scope.
<a4j:keepAlive beanName="results" />
The same story applies to disabled attribute by the way.
See also:
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
JSF 1.2: How to keep request scoped managed bean alive across postbacks on same view?
I think that with the rendered attribute and anything inside you have to take care that the evaluation of it is the same on the initial request AND the submit. It may change just before the render phase but if its not the same during application invoke it will most likely ignore the action if in this phase the button would not be rendered.
As far as i remember this happend for me mostly when the rendered expression uses something like an entity attribute that will be changed during the apply request values phase already.

p:dialog closes when valueChangeListener is invoked

I have a <p:dialog> which contains a <h:selectOneMenu> with a valueChangeListener. Here's the relevant code:
<p:dialog>
<h:form>
<div>
<h:selectOneMenu value="#{itemController.itemId}" valueChangeListener="#{itemController.chkItemType}" onchange="submit()">
<f:selectItems value="#{itemController.itemsList}" />
</h:selectOneMenu>
</div>
</h:form>
</p:dialog>
When it is called, the dialog get closed. I would like to keep it open and only close it on cancel button. How can I achieve this?
That's expected behaviour. The onchange="submit()" which you've there submits the entire form synchronously, causing a complete page reload.
You should be using ajax instead to perform the submit. Replace the onchange attribute by just this tag
<f:ajax />
inside the <h:selectOneMenu>. This way the form will be submitted asynchronously, with by default no page reload at all.
Depending on the concrete functional requirement, which you didn't tell anything about, you do probably also not need a valueChangeListener at all, but rather a <f:ajax listener>.
<f:ajax listener="#{itemController.chkItemType}" />
If you'd like to update some parts of the page on successful execution of the ajax request, use its render attribute.
See also:
When to use valueChangeListener or f:ajax listener?

JSF ReRender support with selectBooleanCheckbox

I have a JSF page on which I want to have a checkbox that, when clicked, will add/remove certain other form fields from the page. Here is the (simplified) code I currently have for the checkbox:
<h:selectBooleanCheckbox title="showComponentToReRender" value="#{backingBean.showComponentToReRender}">
<a4j:support event="onsubmit" reRender="componentToReRender" />
</h:selectBooleanCheckbox>
Here is the code for the component I want to hide:
<h:selectOneMenu id="componentToReRender" value="#{backingBean.value}" rendered="#{valuesList.rowCount>1 && backingBean.showComponentToReRender}">
<s:selectItems value="#{valuesList}" var="value"/>
</h:selectOneMenu>
Currently, clicking the checkbox does nothing; that "selectOneMenu" will not go away. What am I doing wrong?
You need to wrap the componentToReRender in either:
<h:panelGroup id="componentToReRenderWrapper">
or
<a4j:outputPanel id="componentToReRenderWrapper">
So, effectively you will have:
<h:panelGroup id="componentToReRenderWrapper">
<h:selectOneMenu id="componentToReRender" value="#{backingBean.value}" rendered="#{valuesList.rowCount>1 && backingBean.showComponentToReRender}">
<s:selectItems value="#{valuesList}" var="value"/>
</h:selectOneMenu>
</h:panelGroup>
and change the reRender="componentToReRenderWrapper" in case you use panelGroup, or remove that attribute, in case you use outputPanel.
Found the exact explanation in the RichFaces docs:
Most common problem with using reRender is pointing it to the component that has a "rendered" attribute. Note, that JSF does not mark the place in the browser DOM where the outcome of the component should be placed in case the "rendered" condition returns false. Therefore, after the component becomes rendered during the Ajax request, RichFaces delivers the rendered code to the client, but does not update a page, because the place for update is unknown. You need to point to one of the parent components that has no "rendered" attribute. As an alternative, you can wrap the component with layout="none" .
Don't forget to set ajaxRendered="true" on the a4j:outputPanel

Resources