Making h:panelGroup clickable, and send back repeated variable - ajax

I need to make a panelGrid (one of man that are populated from a list of objects) clickable, and then send the item associated with it to the backing bean.
My HTML so for:
<ui:repeat var="searchItem" value="#{bean.filteredSearchItems}" varStatus="searchResult">
<h:panelGrid>
<!-- I get some info here from the searchResult object -->
</h:panelGrid>
<f:ajax event="click" listener="{bean.clickFlight}" />
<f:param name="lfi" value="#{searchResult.index}" />
</ui:repeat>
I know that (in my backing bean) I need a function called clickSearchItem() that can handle the ajax call, so to test all of this, I did the following in my backing bean:
public void clickFlight()
{
HttpServletRequest req = (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
String lfi = req.getParameter("lfi");
if (lfi == null)
log.info("LFI WAS RETURNED AS NULL :(");
log.info("HOPEFULLY AN INDEX OF SOME SORT!: " + lfi);
}
Nothing is getting logged - the click doesn't register. Has anyone else had this problem? Does anyone know how to solve it?

The <f:ajax> needs to be nested into a component implementing ClientBehaviorHolder. If you intend to use <h:panelGrid> (which generates a HTML <table>) for that, then you should be nesting the <f:ajax> in the component itself.
<h:panelGrid>
<f:ajax event="click" listener="{bean.clickFlight}" />
<!-- I get some info here from the searchResult object -->
</h:panelGrid>
The <f:param> is only recognized by renderer of <h:outputFormat> and <h:commandXxx>. Provided that you're targeting a Servlet 3.0 compatible container (Tomcat 7, Glassfish 3, JBoss 6/7, etc) which thus supports EL 2.2, then you can just pass it as method argument instead:
<h:panelGrid>
<f:ajax event="click" listener="{bean.clickFlight(searchResult.index)}" />
<!-- I get some info here from the searchResult object -->
</h:panelGrid>
you can even pass the whole object if preferred:
<h:panelGrid>
<f:ajax event="click" listener="{bean.clickFlight(searchResult)}" />
<!-- I get some info here from the searchResult object -->
</h:panelGrid>
An alternative, if you need <f:param> per se, would be to use <h:commandLink> instead.
<h:commandLink>
<f:ajax event="click" listener="{bean.clickFlight(searchResult)}" />
<f:param name="lfi" value="#{searchResult.index}" />
<h:panelGroup>
<!-- I get some info here from the searchResult object -->
</h:panelGroup>
</h:commandLink>

Related

Ajax request and attributes

I am trying this tutorial which describes how to set attributes into server call and how to analyse the attributes on backing bean;
<h:commandButton id="submit"
actionListener="#{userData.attributeListener}" action="result">
<f:attribute name="value" value="Show Message" />
<f:attribute name="username" value="JSF 2.0 User" />
</h:commandButton>
I googled a lot but most examples show how to set attrs for synch-ed calls not the asynch-ed ones :S So my question is ... how to send attributes on server if that would be the ajax call and how to get them on backing bean (see suggestion A code snippet)?
suggestion A :
<h:commandButton id="submit"
actionListener="#{userData.attributeListener}" action="result">
<f:ajax>
<f:attribute/>? how to
</f:ajax>
</h:commandButton>
and if there is a good tutorial concerning to this question please do share the link :)
Thanks
OK I just wrote a test which sets attributes out the ajax block as :
<h:commandButton id="submit"
actionListener="#{userData.callWithAttributes}" action="result">
<f:attribute name="a" value="#{testa}"/>
<f:attribute name="b" value="#{testb}"/>
<f:ajax .../>
</h:commandButton>
...and on the backing bean
...
public void callWithAttributes(ActionEvent e){
String a=(String) e.getComponent().getAttributes().get("a");
...
}
...
Seems like it's working fine :) So attributes should be placed into event-making component block - the h:commandButton in this particular case...
To set two properties in backing bean you can use f:setPropertyActionListener
<h:commandButton action="#{bean.method}">
<f:setPropertyActionListener value="#{testA}" target="#{bean.valueA}/>
<f:setPropertyActionListener value="#{testB}" target="#{bean.valueB}/>
</h:commandButton>
or with EL method argument support:
<h:commandButton action="#{bean.method(testA, testB)}"/>

Access all ajax UIComponents passed by execute attribute in backing bean?

The following code is a simple form used with ajax component:
<h:form id="loginform">
<h:inputText id="username">
<f:ajax event="blur" execute="loginform:username loginform:loginbutton" ... />
</h:inputText>
<h:inputText id="password">
<f:ajax event="blur" execute="loginform:password loginform:loginbutton" ... />
</h:inputText>
<h:commandButton id="loginbutton" value="login" action="#{indexBean.authentication()}" />
</h:form>
I understand that execute attribute is a space-separated List of IDs for components that should be included in the Ajax request.
I can access the source component at backing bean with AjaxBehaviorEvent.getComponent() method, but how to access the rest of components?
It's available by PartialViewContext#getExecuteIds().
FacesContext context = FacesContext.getCurrentInstance();
Collection<String> executeIds = context.getPartialViewContext().getExecuteIds();
// ...
You can then use UIViewRoot#findComponent() to find component by client ID.
for (String executeId : executeIds) {
UIComponent component = context.getViewRoot().findComponent(executeId);
// ...
}

JSF - commandbutton in newly AJAX rendered form doesn't fire

In my JSF 2.2 application on Glassfish 4.0, i need to allow update of single fields within a page.
For each field, i created a h:form containing two ui:fragments.
Each of there fragments is rendered based on the value of a boolean edit attribute named enteEdit in my backing bean FascicoloDettaglio.
FascicoloDettaglio is #ViewScoped.
The first fragment contains an h:outputText with the value from my bean, and a h:commandLink used to update the edit attribute and fire an AJAX request to re-render the form, which causes the first fragment to disappear and the second fragment to appear.
The second fragment contains the h:inputText used to edit the field, and the submit h:commandButton, which resets the edit attribute and then AJAX-calls the action method.
However, the second button never works; the action is not called and the button simply does nothing; while it should call the action and then re-render the entire form, turning the second fragment off and the first on.
I can't understand why it doesn't work.
This is the JSF code fragment:
<h:form>
<ui:fragment rendered="#{not fascicoloDettaglio.enteEdit}">
<h:outputText value="#{fascicoloDettaglio.fascicolo.ente}" />
<h:commandLink rendered="#{request.isUserInRole('affgen')}">
<h:graphicImage name="img/modify.png" width="24" height="24" title="Modifica" />
<f:ajax render="#form" />
<f:setPropertyActionListener target="#{fascicoloDettaglio.enteEdit}" value="true" />
<f:setPropertyActionListener target="#{fascicoloDettaglio.ente}" value="#{fascicoloDettaglio.fascicolo.ente}" />
</h:commandLink>
</ui:fragment>
<ui:fragment rendered="#{fascicoloDettaglio.enteEdit}">
<h:inputText value="#{fascicoloDettaglio.ente}" requiredMessage="Introdurre l'ente ricorrente." required="true" styleClass="largetext #{component.valid ? '' : 'inputvalidationerror'}">
<f:validateLength maximum="255" />
</h:inputText>
<h:commandButton action="#{fascicoloDettaglio.salvaEnte}" value="Salva">
<f:setPropertyActionListener target="#{fascicoloDettaglio.enteEdit}" value="false" />
<f:ajax execute="#form" render="#form" />
</h:commandButton>
<h:messages />
</ui:fragment>
</h:form>
Any help would be very appreciated.

JSF2: cannot get data from a HtmlSelectOneMenu in java code

I am working with MyFaces/Primefaces and I have a problem to get information using ajax.
My page contains a list of panel, inside each panel, the user can select value in a dropdown list, and click on a checkbox which will update its panel (Ajax), I hope I am clear.
This is my code:
<p:panel>
...
<h:selectOneMenu id="beanSet" value="#{myBean.selectedSet}">
<f:selectItem itemLabel=" " noSelectionOption="true" />
<f:selectItems value="#{langSet}" />
</h:selectOneMenu>
<h:selectBooleanCheckbox
id="chkbxBeanSet"
value="#{myBean.selectedSetChkbx}" >
<p:ajax
event="click" render="#parent"
listener="#{action.updateSet}"
execute="#form"
immediate="true"
/>
</h:selectBooleanCheckbox>
...
<p:panel>
And here my java code:
public void updateSet(AjaxBehaviorEvent e) {
UIComponent source = (UIComponent)e.getSource();
System.out.println("Value:"+((HtmlSelectBooleanCheckbox)source).getValue());
UIComponent parent = source.getParent();
List<UIComponent> children = parent.getChildren();
HtmlSelectOneMenu lvSet = (HtmlSelectOneMenu)parent.findComponent("beanSet");
Object value = lvSet.getValue();
System.out.println("value: " + value);
I get the beanSet component, but I can't get its value. As I understand, the getValue calls the getSelectedSet from myBean which is not set (it is in request scope).
I don't understant how I can get the selected value in the dropdown list using ajax.
Another way is to post all the form, but in that case, I have to determine which checkbox was clicked by the user...
If someone can explain me where I am wrong?
The culprit is immediate="true" on the ajax action. This will skip all input components which do not have this attribute set during the processing. You should finetune the to-be-processed components in the process attribute of <p:ajax>. Yes, another culprit is that you used execute instead of process. The <p:ajax> uses process where <f:ajax> uses execute. Also, the way how you accessed the dropdown value is unnecessarily overcomplicated. Just access the selectedSet property directly. JSF will set it in the same bean anyway.
So, this should do
<h:selectOneMenu id="beanSet" value="#{myBean.selectedSet}">
<f:selectItem itemLabel=" " noSelectionOption="true" />
<f:selectItems value="#{langSet}" />
</h:selectOneMenu>
<h:selectBooleanCheckbox id="chkbxBeanSet" value="#{myBean.selectedSetChkbx}">
<p:ajax process="#this beanSet" listener="#{action.updateSet}" update="#parent" />
</h:selectBooleanCheckbox>
with
public void updateSet() {
System.out.println(selectedSet);
}
Note that I omitted event="click" from <p:ajax>. It's already the default for checkboxes.
place this (listener is optional) , the <f:ajax event="change" is what you need the most
<f:ajax event="change" render="IdsOfComponentToRender" listener="#{myBean.someMethod}" />
inside your <h:selectOneMenu id="beanSet" value="#{myBean.selectedSet}">
this is the signature of the listener
public void someMethod(AjaxBehaviorEvent ev) {...
b.t.w what is that updateLvSet method , and where you call it , and you should not access you data that way...

How to save 2 dependent selectOneMenu values

I'm running in a little issue here regarding jsf related dropdown selection.
I have 2 dropdown selection: the first one is independent, the second one shows result depending from This is the code:
<h:panelGroup id="addressPanel">
<h:outputLabel styleClass="label" value="Provincia: " />
<h:selectOneMenu onchange="updateCombos()"
value="#{indirizzoCtrl.codiceProvincia}" >
<f:selectItem itemValue="" itemLabel=""></f:selectItem>
<f:selectItems value="#{indirizzoCtrl.allProvincia}" var="c"
itemLabel="#{c.nome}" itemValue="#{c.siglaProvincia}" />
</h:selectOneMenu>
<h:outputLabel styleClass="label" value="Comune: " />
<h:selectOneMenu
value="#{indirizzoCtrl.codiceComune}" >
<f:selectItem itemValue="" itemLabel=""></f:selectItem>
<f:selectItems value="#{indirizzoCtrl.allComuni}" var="c"
itemLabel="#{c.descrizione}" itemValue="#{c.codiceComune}" />
</h:selectOneMenu>
</h:panelGrid>
</h:panelGroup>
<p:remoteCommand name="updateCombos" update="addressPanel masterForm:msg" />
<p:commandButton styleClass="commandButton" value="Save"
actionListener="#{indirizzoCtrl.save}">
</p:commandButton>
Well, when the user save the form after selecting both the value, the managed bean indirizzoCtrl (request scoped) cannot map the value of the second dropdown back to the list, because there's no list.
In fact the #{indirizzoCtrl.allComuni} call a getter that retrieve the data from the DB only if indirizzoCtrl.codiceProvincia!=null... and that's false before the update model phase.
So the first time the getter for the list is called cannot retrieve any values, and that's bring the update model phase to fail.
How can I handle this scenario... I think it's a pretty common one, so I'm missing something here...
Put the bean in the view scope instead. It will live as long as you're interacting with the same view by ajax. A request scoped bean get indeed recreated on every single request, also ajax requests, so bean properties would reinitialize to their defaults.
#ManagedBean
#ViewScoped
public class IndidizzoCtrl implements Serializable {
// ...
}
See also:
How to load and display dependent h:selectOneMenu on change of a h:selectOneMenu
How to choose the right bean scope?
Unrelated to the concrete problem, I also strongly recommend to change your getter methods to not do any business job, but just return data. Do the business job in (action)listener methods instead. E.g.
<h:selectOneMenu value="#{bean.menu1item}">
<f:selectItems value="#{bean.menu1items}" />
<f:ajax listener="#{bean.updateMenu2}" render="menu2" />
</h:selectOneMenu>
<h:selectOneMenu id="menu2" value="#{bean.menu2item}">
<f:selectItems value="#{bean.menu2items}" />
</h:selectOneMenu>
with
public void updateMenu2() {
menu2items = loadItBasedOn(menu1item);
}
See also:
Why JSF calls getters multiple times

Resources