I have a loop with a bunch of h:selectBooleanCheckboxs inside a ui:repeat and I want to be able to check / uncheck all of them with one click. Following this this is how I try to do it:
<h:selectBooleanCheckbox value="#{bean.selectAll}" valueChangeListener="#{bean.selectAllCustomers}">
<f:ajax execute="#form" render="entireLoop"/>
</h:selectBooleanCheckbox>
The loop:
<h:panelGroup id="entireLoop">
<ui:repeat var="customer" varStatus="status" value="#{bean.customers}">
<tr>
<td>
<h:selectBooleanCheckbox value="#{bean.customersMap[customer]}"/>
</td>
<td><h:commandLink value="#{customer.userID}" action="#{navBean.gotoEditCustomer(customer)}"/></td>
<td>#{bean.getContact(user)}</td>
<td>#{customer.companyName}</td>
<td>#{customer.email}</td>
<td>#{customer.phone}</td>
</tr>
</ui:repeat>
</h:panelGroup>
The code in the bean:
public void selectAllCustomers() {
Iterator<User> keys = customersMap.keySet().iterator();
while(keys.hasNext()) {
User user = keys.next();
customersMap.put(user, selectAll);
}
}
When I click to check the "select all" checkbox, I have two problems:
Nothing happens. Only when I click on somewhere else in the page the method is called. How can I get it to go directly?
The entire loop disappears from the page. Why? (I tried to get the ajax to render only the selectBooleanCheckbox by giving it an id, or a name, but I'm getting an error saying this is not a naming component.)
Instead of using valueChangeListener, your method will work if you use the listener attribute of the <f:ajax> tag. It would be something like this:
<h:selectBooleanCheckbox value="#{bean.selectAll}">
<f:ajax listener="#{bean.selectAllCustomers}" render="entireLoop"/>
</h:selectBooleanCheckbox>
Besides, you don't need to submit the whole form with execute="#form". You only need to submit selectAll property and re-render the entireLoop.
If you really want to use valueChangeListener, you must note that your method will be triggered before the new value is applied in the selectAll property. As a result, your entireLoop will not be updated until the next request. To use valueChangeListener, your listener method should look like this:
public void selectAllCustomers(ValueChangeEvent e) {
boolean newSelectAll = (Boolean) e.getNewValue();
Iterator<Users> keys = customersMap.keySet().iterator();
while(keys.hasNext()) {
Users user = keys.next();
customersMap.put(user, newSelectAll);
}
}
Related
I am trying to migrate some functionality from JQuery to JSF and I am getting strange results.
Basically it is a page where you can navigate links (imagine like a Windows Explorer on the Web). Folders have a link and leafs don't. To construct this, it is used a private List<Element> list;, which is refreshed accordingly. So when the user clicks on a "folder", a new list is created with the contents of that folder.
The problem is that I am getting strange results. Sometimes I navigate a link and it is refreshed correctly, but in some cases it behaves like the page is reloaded (but it is not) and the list is reset to its initial values (?). For example, I navigate to "name2" and get the right things. But then I go to "name2b" and I instead of the leafs I get "name1", "name2" and "name3", which are only set in the init() method. I don't know how this happens, but exploring the source code it seems that the c:foreach structure is messing with the ids and an old ID is rendered in the page (note that I have tried ui:repeat with same incorrect results).
How can I fix this?
This is the simplified code:
<f:metadata>
<f:viewAction action="#{controller.init}" />
</f:metadata>
...
<h:panelGroup id="visor" layout="block">
<ul>
<c:forEach items="#{controller.list}" var="element">
<li>
<ui:fragment rendered="#{element.folder}">
<h:form>
<h:commandButton action="#{controller.navigate(element.name)}" type="submit" value="#{element.name}" >
<f:ajax render="visor" execute="#this" />
</h:commandButton>
</h:form>
</ui:fragment>
<ui:fragment rendered="#{not element.folder}">
<span>#{element.name}</span>
</ui:fragment>
</li>
</c:forEach>
</ul>
</h:panelGroup>
And the controller
#Named(value = "controller")
#ViewScoped
public class MyController implements Serializable {
private List<Element> list;
public void init() { //Called when loading the page
list = new ArrayList<>();
Element e1 = new Element("name1", true); //name and isFolder?
Element e2 = new Element("name2", true);
Element e3 = new Element("name3", true);
list.add(e1);
list.add(e2);
list.add(e3);
}
public void navigate(String name) {
list = new ArrayList<>();
if (name.equals("name1")) {
Element e1 = new Element("name1a", true);
Element e2 = new Element("name1b", true);
Element e3 = new Element("name1c", true);
list.add(e1); list.add(e2); list.add(e3);
} else if (name.equals("name2")) {
Element e1 = new Element("name2a", true);
Element e2 = new Element("name2b", true);
Element e3 = new Element("name2c", true);
list.add(e1); list.add(e2); list.add(e3);
} else {
Element e1 = new Element("leaf1", false);
Element e2 = new Element("leaf2", false);
list.add(e1); list.add(e2);
}
}
//....
EDIT
My problem seems to be described in here.
I have to investigate if this question can bring some light to the subject.
Apparently it is a well-known thing that my structure cannot be dynamically updated in JSF. The solution I have to make is to use a h:datatable instead of a <ul> list (this is one thing I really dislike of JSF, but I am not sure how to render a list with basic JSF - instead of a table, that I can dynamically update.
The Ajax render attribute had to specify the form id.
<h:form id="visor">
<h:dataTable value="#{controller.list}" var="element">
<h:column>
....
<h:commandButton action=.... >
<f:ajax render="visor" execute="#this" />
</h:commandButton>
....
</h:column>
</h:dataTable>
</h:form>
Edit: The UL also worked, as long as I render the form and the form contains everything
Im using a primefaces FieldSet component and have a button field specified inside the field set. I have a requirement, Where, when I click on the command button, a h:selectonemenu & an inputtext should be displayed and On further click, the h:selectOnemenu &inputtext should be hidden. Below is the code that I have written to show & hide. The show part works fine. But when I try to click on the button to hide, it does not work.
xhtml code
<h:panelGrid id="grid1" columns="3">
<p:fieldset id="GlobalAdjustment" legend="GlobalAdjustment" style="font-size:12px !important;width:30%" >
<h:commandButton id="globalAdjustID" image="#{review.imageUrl}" actionListener="#{review.showUpdateList}" />
</p:fieldset>
<h:selectOneMenu id="SelectID" value="#{review.reviewList}" rendered="#{demandReview.selectoneRenderer}">
<f:selectItems id="FilterSelectListID" value="#{review.reviewListIDs}" style="font-size:12px !important"></f:selectItems>
</h:selectOneMenu>
<h:inputText id="fieldUpdateID" required="false" rendered="#{review.inputTextRenderer}"></h:inputText>
</h:panelGrid>
ManagedBean ActionListener method
public void showUpdateList(ActionEvent event)
{
System.out.println("entering the Action Method:");
Map<String, Object> idMap = new HashMap<String, Object>() ;
idMap = event.getComponent().getAttributes();
String url = (String) idMap.get("image");
System.out.println("The url is :"+url);
if(url.equals("/images/add_data_button.png")){
//upbean.setImageUrl("/images/remove_data_button.png") ;
imageUrl ="/images/remove_data_button.png" ;
selectoneRenderer = true;
inputTextRenderer = true;
}else
{
imageUrl ="/images/add_data_button.png" ;
selectoneRenderer = false;
inputTextRenderer = false;
}
}
When I click the command button inside the fieldset for the first time, it works fine and displays the selectoneMenu & the textbox. Once further clicks, the ActionListener is not getting invoked. Please help me resolve the issue.
Thanks
You can try another approach. Use p:commandButton with an update attribute like this:
<h:panelGrid id="grid1" columns="3">
<p:fieldset id="GlobalAdjustment" legend="GlobalAdjustment" style="font-size:12px !important;width:30%" >
<p:commandButton id="globalAdjustID" image="#{review.imageUrl}" actionListener="#{review.showUpdateList}" update="grid1"/>
</p:fieldset>
<h:selectOneMenu id="SelectID" value="#{review.reviewList}" rendered="#{demandReview.selectoneRenderer}">
<f:selectItems id="FilterSelectListID" value="#{review.reviewListIDs}" style="font-size:12px !important"></f:selectItems>
</h:selectOneMenu>
<h:inputText id="fieldUpdateID" required="false" rendered="#{review.inputTextRenderer}"></h:inputText>
</h:panelGrid>
This way you'll use partial processing and the conditional renderization of the panel's inner components will be done through AJAX.
Also, it could be a good idea to check your server's console to see if there are any messages in the queue that were not displayed.
Does the requirement specify using the server side? For something like this, I would have thought a simple Javascript script would have been better suited.
For example, use the jQuery library to do something like:
<h:commandButton id="xyz" onclick="$('#elementId').toggle();"/>
I was playing around with primefaces components, when I stumbled upon this issue...
I have a sample page which contains the following,
<h:form>
<p:panel id="p1">
<p:commandButton value="display" actionListener="#{myTestBean.display}" update="p2"> </p:commandButton>
</p:panel>
<p:panel id="p2" rendered="#{myTestBean.show}">
<p:inputText value="#{myTestBean.val1}" id="t1"></p:inputText>
<p:inputText value="#{myTestBean.val2}" id="t2"></p:inputText>
<p:commandButton value="click me" update="#form" action="#{myTestBean.disply}"></p:commandButton>
</p:panel>
</h:form>
My backing bean contains the following,
public class Testbean implements Serializable {
private String val1;
private String val2;
private boolean show;
//getters and setters for the above...
public void display(){
if(show == false){
setShow(true);
}
}
public void disply(){
System.out.println("I am here");
val1 = "hi";
val2 = "hello";
if(show == false){
setShow(true);
}
}
}
Now, the catch here is, when I click my first button(display) the below panel(p2) gets rendered correctly. But when I click on the second button(click me) the panel gets hidden and also on click of second button it never goes to the backing bean method 'disply()'.
I have used action listener in the second button but again the same behavior. Also, I have given the update = "p2" in the second button, even that didn't yield what I wanted.
Could anyone help me out with this and let me know where and what I am doing wrong?
Thank you.
The bean needs to be placed in the view scope in order to remember all previous (ajax) actions on the same view.
#ManagedBean
#ViewScoped
public class TestBean {
// ...
}
When the bean is placed in the request scope, then the boolean show would be reinitialized to default false and thus the rendered attribute would evaluate false while JSF is looking for the action method to be invoked and hence the action method would be never found and invoked.
See also:
How to choose the right bean scope?
commandButton/commandLink/ajax action/listener method not invoked or input value not updated
When using actionListener="#{myTestBean.display}", the backinbean method should be
public void display(**ActionEvent event**){
if(show == false){
setShow(true);
}
}
and an ActionEvent parameter must be declared.
I surrounded the button as shown below
<h:form>
<h:commandButton styleClass="toggle_btn" action="#{buttonNavBean.show()}" style=" font-family: sans-serif; color: black;" value="Sign In/Sign Up"></h:commandButton>
</h:form>
I faced the same challenge too. I tried to search online but all in vain. But after several trials, I came to figure out that since I was using the commandButton to set the value of the rendered panel, it was not possible to work out of UIForm, Therefore, I surrounded the commandButton with UIForm and it worked correctly as I wanted.
I am using Netbeans 6.9.1. I am using code in which i am simply using selectManyListBox and i want that when user selects all the values then my valueChangeListener is call. Here what i am doing
<h:selectManyListbox id="countryListBox" size="5" value="#{news.saarcCountries}"
onselect="form.submit();" valueChangeListener="#{news.changeAppearOnCountryPage}">
<f:selectItems value="#{news.saarcCountriesMap}"/>
<f:ajax render="countryPageExpiryCalender" />
</h:selectManyListbox>
<p:calendar id="countryPageExpiryCalender" value="#{news.countryPageExpiryDate}"
navigator="true" style="z-index: 1;" locale="en" mode="popup"
pattern="dd/MM/yyyy" showOn="button" readOnlyInputText="true"
disabled="#{!news.appearOnCountryPage}" />
I also tried this, instead of onselect i used onchnage like
onchange="submit()"
Here is my valueChangeListener
#ManagedBean(name = "news")
#ViewScoped
public class News {
private Map<String, String> saarcCountriesMap = new LinkedHashMap<String, String>();
private Set<String> saarcCountries = new TreeSet<String>();
...
public void changeAppearOnCountryPage(ValueChangeEvent vcEvent){
Iterator iter = saarcCountries.iterator();
while(iter.hasNext()) {
String name = (String)iter.next();
System.out.println(name);
}
} //end of changeAppearOnCountryPage
} //end of class News
I want that when user select all the values from the selectmanyListBox, then my valueChangeListener is call, and i check if i have the values in saarcCountries variable, then i set appearOncountryPage = true, so my calender is render. But my valueChangeListener is not calling. What i am doing wrong?
If i choose onselect, then i want to ask one thing this event will trigger whenever i select the value, of after i have selected all the values. I want that when user select all the values then my ValueChangeListener is call and the values that user selected will be in my saarcCountries variable. So i can check the values that user selected.
I think onchange() is not appropriate in my case. Please help. I am stuck because of it:(
Thanks
try it like this:
<h:selectManyListbox id="countryListBox" size="5" value="#{news.saarcCountries}">
<f:selectItems value="#{news.saarcCountriesMap}"/>
<f:ajax event="change" listener="#{news.changeAppearOnCountryPage}" render="countryPageExpiryCalender"/>
</h:selectManyListbox>
You don't need the form.submit(); since you can use the ajax...
JSF 2.0 (mojarra) application. I have a very trivial form for adding an item
<h:form>
#{msg['add custom title']}:<br />
<table>
<tr>
<td>#{msg['heaading']}:</td>
<td><h:inputText value="#{titlesBean.title.heading}"></h:inputText></td>
</tr>
<tr>
...
</tr>
</table>
<h:commandButton action="#{titlesBean.addTitle}" value="#{msg['g.save']}" />
</h:form>
And then on the same page I have a list of all the items already added:
<h:dataTable id="manualTitlesForm" value="#{titlesBean.manualTitles}" var="title" border="1" cellspacing="0">
<h:column>
<f:facet name="header">#{msg['heaading']}</f:facet>
#{title.heading}
</h:column>
...
<h:column>
<f:facet name="header">#{msg['actions']}</f:facet>
<h:form>
<h:commandButton action="#{titlesBean.editManualTitle(title)}" value="#{msg['g.edit']}" />
<h:commandButton action="#{titlesBean.deleteManualTitle(title.id)}" value="#{msg['g.delete']}" />
</h:form>
</h:column>
</h:dataTable>
The code in the bean code is super simple:
#Controller
#Scope(Scopes.REQUEST)
public class TitlesBean {
private List<JTitle> manualTitles;
#PostConstruct
private void init() {
this.manualTitles = titlesManager.getManualTitles();
}
public String addTitle() {
title.setCreated(new Date());
title.setManual(true);
try {
titlesManager.addTitle(title);
title = new JTitle();// this is added, delete from the variable. only if no exception though !!!
UserMessagesBean.addMessage("saved");
} catch (Exception e) {
UserMessagesBean.setValidationException(e.getMessage());//different exception added
}
return null;
}
public List<JTitle> getManualTitles() {
return manualTitles;
}
}
Now the problem is that getManualTitles() is called as many times as the number of titles I have, which causes for example 12 calls to the DB, instead of one. Why is this happening is beyond my understanding. I can fix this with caching the manual titles in the bean. This is not my main problem.
The problem is that addTitle() is called AFTER getManualTitles(). In fact getManualTitles() is called for example 10 times, then addTitle(), then two more times the getManualTitles() method. This makes me think that this is some kind of parallel execution which causes my page to show only the 12 old records instead of 13. I have to reload the page, then 13 is shown.
UPDATED: now caches the list. Problem still not solved.
WHY? How can I fix this?
This is a quick fix, but not a real solution. Redirect the result of addTitle():
Add the following to addTitle():
...
FacesContext.getCurrentInstance().getExternalContext()
.redirect("manualTitles.jsf");
return null;
}