Suppose I have two selectOneMenu tags bound to two different lists (let's say Products and Departments).
I want to prevent choosing some Departments depending on the Product selected and vice versa. Where could I put that logic?
Not sure if this is the way you want to go about for this. But you can load the Department list base on the selection of Product. To do this you need to send Ajax request to update the Department list when you select a Product. To illustrate this, I will use PrimeFaces to send out ajax request
<h:selectOneMenu id="product" value="#{bean.selectedProduct}">
<f:selectItem itemLabel="Select Product" itemValue="" />
<f:selectItems value="#{bean.productList}"/>
<!-- here is where I send out ajax request -->
<p:ajax listener="#{bean.loadDepartmentById}" event="change" update="department" />
</h:selectOneMenu>
<h:selectOneMenu id="department" value="#{bean.selectedDepartment}">
<f:selectItem itemLabel="" itemValue="" />
<f:selectItems value="#{bean.departmentList}"/>
</h:selectOneMenu>
Here is my bean
#ManagedBean
#ViewScoped
public class bean{
private List<SelectItem> productList = null;
private List<SelectItem> departmentList = null;
private Long selectedProduct = null;
private Long selectedDepartment = null;
#PostConstruct
public void init(){
//Pre load product list
productList = new ArrayList<SelectItem>();
productList.add(new SelectItem("value1", "label1"));
productList.add(new SelectItem("value2", "label2"));
productList.add(new SelectItem("value3", "label3"));
//The values are the keys passed to the selectItem property.
//The labels are those what you see on the menu.
}
public void loadDepartmentById(){
if(selectedProduct != null){
//Load the appropriate list of department.
}
}
}
Related
Cant understand <h:selectOneMenu> component. Tried many ways to pass parameter from dropdown to java, and 4 different ways to call java method. First two ways (onchange and commandbutton doesnt call java) other two does, but works badly as it cant set selectedItem to java variable:
<h:form id="tasks">
<h:selectOneMenu id = "selectonemenu" value="#{services.selectedItem}"
immediate="true" onchange="javascript: return this.form.submit();">
<f:selectItems value="#{services.selectItems}" />
</h:selectOneMenu>
<h:commandButton value = "StringHello" action="#{services.StringHelo}" />
<s:link action="#{services.StringHello}" reRender="tasks"></s:link>
<a:commandLink id="aclink"
action="#{services.StringHello}"
ajaxSingle="true" eventsQueue="globalQueue"
ignoreDupResponses="true" requestDelay="0"
onComplete="return false;"
status="globalStatus">
aclink
</a:commandLink>
<h:outputText id = "valueofselected" value = "#{services.selectedItem}"/>
</h:form>
And Services.Java:
private String selectedItem;
public String getSelectedItem() {
if (selectedItem == null) {
selectedItem = "All"; // This will be the default selected item.
}
System.out.println("getSelectedItem "+selectedItem);
return selectedItem;
}
public void setSelectedItem(String selectedItem) {
this.selectedItem = selectedItem;
System.out.println("setSelectedItem");
}
public List getSelectItems() {
List selectItems = new ArrayList();
selectItems.add(new SelectItem("All", "All"));
selectItems.add(new SelectItem("A", "A"));
selectItems.add(new SelectItem("B", "B"));
selectItems.add(new SelectItem("C", "C"));
selectItems.add(new SelectItem("D", "D"));
System.out.println("getSelectItems: "+selectItems.size());
return selectItems;
}
public void StringHello(){
System.out.println(" SelectedItem - "+selectedItem);
}
returns null in console:
14:41:51,897 INFO [STDOUT] SelectedItem - null
but i can see that outputText's value is always "All" and in console i see every time when getSelectedItem method is called:
14:41:49,087 INFO [STDOUT] getSelectedItem All
Also, i think it's very important: after i choose any value, page refreshes and it becomes default 'All' value again.
Do you really want to send the whole form (do a form submit)?
Try this, there should be no page refresh:
<h:form id="tasks">
<h:selectOneMenu value="#{services.selectedItem}">
<f:selectItems value="#{services.selectItems}" />
<f:ajax execute="#this" render="result"/>
</h:selectOneMenu>
<h:outputText id="result" value="#{services.selectedItem}"/>
</h:form>
#ujulu was right, i created separate java class with #Scope(ScopeType.SESSION) and my form was located at wrong place, i moved it higher in hierarchy, to get rid of any parent components. And it works now.
i have a p:selectOneMenu filled with objects from database.When page is looaded first,
the default item of selectOneMenu must be "please select one" in string type( other items of selectOneMenu are in object type.) When page is loaded first, one data in object type from database is visible as default.I don't want this.how to set default item like "Please select one" in p:selectOneMenu with object from database?
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:f="http://java.sun.com/jsf/core"
template="layout.xhtml">
<ui:define name="pageContent">
<h:form id="silYapilandirmaForm" prependId="true">
<p:panel id="silYapilandirmaPanel" header="#{etiketler.silYapilandirma}" collapsed="true" toggleable="true" >
<p:tabView id="tabView" dynamic="false" activeIndex="0">
<p:tab title="#{etiketler.silIslemleri}" id="silIslemleriTab">
<p:outputPanel id="silIslemleriPanel">
<h:panelGrid id="eshsSecPanelGrid" columns="3" >
<h:outputText value="#{etiketler.eshsSertifika}:*" />
<p:selectOneMenu id="silYapilandirmaSelect" value="#{silYapilandirmaView.seciliEshsSertifika}" effect="fade" effectDuration="100" style="width: 205px" converter="#{entityConverter}">
<f:selectItem itemLabel="Please select one" itemValue="#{null}"/>
<f:selectItems value="#{silYapilandirmaView.eshsSertifikaList}" var="eshsSertifika"
itemLabel="#{eshsSertifika.sertifikaKodAdi}" itemValue="#{eshsSertifika}" />
<p:ajax process="#this" event="change" update="eshsSecPanelGrid,silIslemleriPanel" listener="#{silYapilandirmaView.addListener()}" />
</p:selectOneMenu>
<h:outputText value=""/>
<h:outputText value="#{etiketler.eshsSertifika}:" />
<h:inputText value="#{silYapilandirmaView.seciliEshsSertifika.sertifikaKodAdi}" disabled="true" size="30"/>
<h:outputText value=""/>
<h:outputText value="#{etiketler.silUretimBaslangicSaati}:* " />
<p:inputMask id="silUretimBaslangicSaatiInputMask" value="#{silYapilandirmaView.seciliEshsSertifika.silUretimBaslangicSaati}" mask="99:99:99" size="30" />
<p:message for="silUretimBaslangicSaatiInputMask" display="text" />
<h:outputText value="#{etiketler.silUretimBaslangicPeriyodu}:* " />
<p:inputMask maxlength="4" mask="99?99" id="periyotInputMask" size="30" value="#{silYapilandirmaView.seciliEshsSertifika.silUretimPeriyodu}" >
</p:inputMask>
<p:message for="periyotInputMask" display="text" />
</h:panelGrid>
</p:outputPanel>
</p:tab>
</p:tabView>
</p:panel>
</h:form>
</ui:define>
</ui:composition>
i have addListener method in p:ajax in p:selectOneMenu.This method is working in this way;
you are selecting one object from selectOneMenu and this object is put in the last index of the list filling selectOneMenu ,the object in the last index of the list is put in the index of selected object.I mean you are selecting an object and the index of this object in the list is 2.In total there are five objects in the list ,let we say.selected object whose index is 2 is put in index 4 of the list.The object in index 4 of the list is put in index 2 of the list.I am sorry for my english.The aim of this addListener method,selectOneMenu displays the last item of the list as selected always.Whichever object you select,IT DISPLAYS THE LAST ITEM OF THE LIST.Therefore due to this method , the object i selected is put in the last of the list and it displays as selected to user.The method works fine.
But when page is loaded first , the last item of the list is shown as selected in p:selectOneMenu ,i want "please select" to be shown as default."
My bean class is SilYapilandirmaView.java
#ManagedBean
#ViewScoped
public class SilYapilandirmaView extends BaseView implements Serializable {
#ManagedProperty("#{commonService}")
private CommonService commonService;
private EshsSertifika seciliEshsSertifika;
private List<EshsSertifika> eshsSertifikaList;
#PostConstruct
public void init() {
seciliEshsSertifika=new EshsSertifika();
eshsSertifikaList = (List) commonService.hepsiniGetir(EshsSertifika.class);
seciliEshsSertifika = eshsSertifikaList.get(eshsSertifikaList.size() - 1);
}
public CommonService getCommonService() {
return commonService;
}
public void setCommonService(CommonService commonService) {
this.commonService = commonService;
}
public void addListener() {
if(seciliEshsSertifika ==null)
{
return;
}
int i = 0;
for (EshsSertifika eshsSert : eshsSertifikaList) {
if (seciliEshsSertifika.getId() == eshsSert.getId()) {
eshsSert = eshsSertifikaList.get(eshsSertifikaList.size() - 1);
eshsSertifikaList.set(i, eshsSert);
eshsSertifikaList.set(eshsSertifikaList.size() - 1, seciliEshsSertifika);
break;
}
i++;
}
}
public EshsSertifika getSeciliEshsSertifika() {
return seciliEshsSertifika;
}
public void setSeciliEshsSertifika(EshsSertifika seciliEshsSertifika) {
this.seciliEshsSertifika = seciliEshsSertifika;
}
public List<EshsSertifika> getEshsSertifikaList() {
return eshsSertifikaList;
}
public void setEshsSertifikaList(List<EshsSertifika> EshsSertifikaList) {
this.eshsSertifikaList = EshsSertifikaList;
}
}
When i added following code in init() method ,my code is working perfectly!
seciliEshsSertifika=null;
public void init() {
seciliEshsSertifika=new EshsSertifika();
eshsSertifikaList = (List) commonService.hepsiniGetir(EshsSertifika.class);
seciliEshsSertifika = eshsSertifikaList.get(eshsSertifikaList.size() - 1);
seciliEshsSertifika=null;
}
when page is loaded, "please select one" is visible in p:selectOneMenu,but i don't want to make "seciliEshsSertifika" object equal to null.,is there anybody else coming up with another solution?
Try this. get the object you want to set the first item. (this example i get the first object in the list)
bean.java
EshsSertifika firstItem = eshsSertifikaList.get(0);
xhtml
<f:selectItem itemLabel="#{eshsSertifika.firstItem.sertifikaKodAdi}" itemValue="#{eshsSertifika.firstItem}" />
I have a dataTable with a list of items and a checkbox for selecting an item to edit. Ticking an item and clicking the edit button pops up a component which has fields and update and cancel buttons. Here's what happens.
Dialog appears
I empty all fields and click UPDATE, required messages appear since all fields are empty, data is not saved
Click CANCEL, dialog disappears
Click and edit the same item again
Some fields are not showing. I checked the datatable and database, data for the item still exists. Just not showing on the edit dialog the 2nd time around.
I noticed that the fields not showing are only those that have NULL attributes. NOT NULL fields are fine. I wonder if this has something to do with sessions. (Using Primefaces for all components)
Code for the edit dialog
<p:dialog header="#{bundle.Edit}" modal="true" widgetVar="editDialog" resizable="false">
<h:form id="edit-form">
<p:messages id="edit-error" autoUpdate="true" closable="true"/>
<h:outputLabel value="#{bundle.Name}" for="name" /><span class="required">*</span>
<p:inputText id="name" value="#{controller.selected.name}" required="true" requiredMessage="#{bundle.Name} #{bundle.FieldIsRequired}" maxlength="45"/>
<h:outputLabel value="#{bundle.Input}" for="input" /><span class="required">*</span>
<h:selectOneRadio id="input" value="#{controller.selected.input}" required="true" requiredMessage="#{bundle.Input} #{bundle.FieldIsRequired}">
<f:selectItem itemLabel="◯ " itemValue="0" />
<f:selectItem itemLabel="☓ " itemValue="1" />
</h:selectOneRadio>
<h:outputLabel value="#{bundle.IsOption}" for="isOption" /><span class="required">*</span>
<h:selectOneRadio id="isOption" value="#{controller.selected.isOption}" required="true" requiredMessage="#{bundle.IsOption} #{bundle.FieldIsRequired}">
<f:selectItem itemLabel="◯ " itemValue="0" />
<f:selectItem itemLabel="☓ " itemValue="1" />
</h:selectOneRadio>
<h:outputLabel value="#{bundle.Remark}" for="remark" />
<p:inputTextarea id="remark" value="#{controller.selected.remark}"/>
<p:commandButton action="#{controller.update()}"
value="#{bundle.Save}"
actionListener="#{controller.prepareList()}"
oncomplete="handleEditDialog(xhr, status, args)"
update=":form:datatable :edit-form:edit-error"
/>
<p:commandButton value="#{bundle.Cancel}"
onclick="editDialog.hide(); reset();"
type="button"/>
</h:form>
</p:dialog>
Code for the update function
public String update() {
RequestContext context = RequestContext.getCurrentInstance();
try {
current.setUpdateDate(new Date());
Map<String, Object> param = JsfUtil.getExternal().getSessionMap();
int createUser = (Integer) param.get("LOGIN_ID");
Account account = accountFacade.find(createUser);
current.setUpdateUser(account);
getFacade().edit(current);
search();
prepareList();
JsfUtil.addSuccessMessage(ResourceBundle.getBundle(JsfUtil.getSessionBundle()).getString("Updated"));
updateOk = true;
current = null;
context.addCallbackParam("updated", true);
return "";
} catch (Exception e) {
if (e.getCause().getCause().getMessage().contains("uk_")) {
JsfUtil.addErrorMessage("edit-form:edit-error",JsfUtil.getResourceString("Duplicate"));
context.addCallbackParam("updated", false);
} else {
JsfUtil.addErrorMessage(e, ResourceBundle.getBundle(JsfUtil.getSessionBundle()).getString("PersistenceErrorOccured"));
context.addCallbackParam("updated", false);
}
return null;
}
}
Based on what you are describing I think the following scenario is happening. When you see the form and you delete all fields and you hit save, the components that have no validators are actually overwriting some of the previous property values of your bean. That's why when you reload it for a second edit, you'll notice that all the components that have a validator attached (e.g required = true) are appearing but those with no validators are blank. In reality, you are actually doing a partial update. What you actually need to do is mark all fields as required to avoid that problem.
My teammate just found out a fix for this one. There is a function on the controller generated by NetBeans called prepareList().
public String prepareList() {
recreateModel();
return "";
}
private void recreateModel() {
items = null;
}
Basically we added this on catch block of the update() function. It is called after every unsuccessful update and recreates the model. The bug existed because the field retained its state of not having a value after an unsuccessful update.
I am trying to implement table with users' accounts, which can be modified by administrators. I use primefaces (2.2) DataTable component with cellEditor.
I have onRowEditListener which uses manageUsers.onEditRow() method to persist changes in database via UserDAO object.
After loading the page and updating table cell - data in database change properly. Unfortunately, when I am trying to update previous row again - (UserDAO)event.getObject(); returns old object (the one after first change) and data are not updated.
When I reload page (F5) and edit row - then data are changed properly.
How can I update table or how can I get the freshest version of user without reloading page?
Using Primefaces 2.2, JSF 2.1, Glassfish 3.1
PAGE:
<p:column headerText="login" filterBy="#{u.user.login}" filterMatchMode="contains" style="width:150px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{u.user.login}" />
</f:facet>
<f:facet name="input">
<h:form>
<p:inputText value="#{u.user.login}" />
</h:form>
</f:facet>
</p:cellEditor>
</p:column>
<p:column headerText="email" filterBy="#{u.user.email}" filterMatchMode="contains" style="width:150px">
<p:cellEditor>
<f:facet name="output">
<h:outputText value="#{u.user.email}" />
</f:facet>
<f:facet name="input">
<h:form>
<p:inputText value="#{u.user.email}" />
</h:form>
</f:facet>
</p:cellEditor>
</p:column>
//... other fields
<p:column headerText="Options">
<p:rowEditor />
</p:column>
</p:dataTable>
</h:form>
ManageBean with ApplicationScope (CDI)
#Named
#ApplicationScoped
public class ManageUsers implements Serializable {
#Inject
/** Inject database */
private DB db;
/** List with all leaked data which is loaded from database */
private List<UserDAO> users;
private User selectedUser;
private SelectItem[] manufacturerOptions;
public ManageUsers() {
manufacturerOptions = createFilterOptions();
}
public SelectItem[] getManufacturerOptions() {
return manufacturerOptions;
}
public User getSelectedUser() {
return selectedUser;
}
public void setSelectedUser(User selectedUser) {
this.selectedUser = selectedUser;
}
/** List of users loaded from database */
public void getDataFromDatabase() {
try {
users = db.getUserList();
if (users == null) {
throw new Exception("Pusta lista użytkowników");
}
} catch (Exception ex) {
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
"Nie można wyświetlić tabeli wyników",
"Nie udało się pobrać danych, prosimy spróbować ponownie później.");
FacesContext.getCurrentInstance().addMessage(null, message);
}
}
/**
* Get list of leaked Data.
* If list is null then getDataFromDatabase method is used.
* #see DataExplorer.getDataFromDatabase()
*/
public List<UserDAO> getUsers() {
if (users == null) {
getDataFromDatabase();
}
return users;
}
private SelectItem[] createFilterOptions() {
SelectItem[] options = new SelectItem[3];
options[0] = new SelectItem("", "-select-");
options[1] = new SelectItem("true", "Admins");
options[2] = new SelectItem("false", "Users");
return options;
}
public void onEditRow(RowEditEvent event){
UserDAO userDAO = (UserDAO)event.getObject();
try {
userDAO.update();
} catch (UserDAOException ex) {
Log.logger.error("User not edited,"+ex);
}
//getDataFromDatabase();
}
}
You are always returning a new list which is a well known bad practice in JSF, fetching data in getter. Getters may be called several times during JSF lifecycle. Cache your user list in a variable and better to use view scope.
Inline edit/update actually works but you are losing the updated model by returning a new list every time.
I don't know if I really understood your problem but you can easily update your table or even better update your form but implementing a commandButton with update attribute:
Let's say you have a form and it's id is myTableForm, then inside that form you have your dataTable component and a commandButton component. This button will look like this:
<p:commandButton ajax='true' value='PersistData' update='myTableForm' action='if really needed' />
You can refer to an action method only if you need to. Otherwise this button will only update your entire form by implementing an ajax request. Ajax is by default true, but I added that attribute there for explicitly.
Of course you can have another logic design...you don't have to implement a button to do that, you could have some ajax listeners, some javascript functions that will be triggered at page load, edit cells etc... I have chosen a commandButton because it's the easiest way to understand the logic...
Please let me know if this was really what you wanted.
Problem solved.
There are extra h:form around p:inputText =_=
I use the google map tool from primefaces.
I want my user to be able to place just one marker on a map.
The values of the coordinates should be stored in a managed bean variables.
How can I do that?
See what I did so far:
I created the map:
<f:view contentType="text/html">
<p:gmap id="gmap" center="36.890257,30.707417" zoom="13" type="HYBRID"
style="width:600px;height:400px"
model="#{mapBean.emptyModel}"
onPointClick="handlePointClick(event);"
widgetVar="map" /> </f:view>
<p:dialog widgetVar="dlg" effect="FADE" effectDuration="0.5" close="false" fixedCenter="true">
<h:form prependId="false">
<h:panelGrid columns="2">
<h:outputLabel for="title" value="Title:" />
<p:inputText id="title" value="#{mapBean.title}" />
<f:facet name="footer">
<p:commandButton value="Add"
actionListener="#{mapBean.addMarker}"
update="messages"
oncomplete="markerAddComplete()"/>
<p:commandButton value="Cancel" onclick="return cancel()"/>
</f:facet>
</h:panelGrid>
<h:inputHidden id="lat" value="#{newOfferSupportController.mapLocationX}" />
<h:inputHidden id="lng" value="#{newOfferSupportController.mapLocationY}" />
</h:form>
</p:dialog>
<script type="text/javascript">
var currentMarker = null;
function handlePointClick(event) {
if(currentMarker == null) {
document.getElementById('lat').value = event.latLng.lat();
document.getElementById('lng').value = event.latLng.lng();
currentMarker = new google.maps.Marker({
position:new google.maps.LatLng(event.latLng.lat(), event.latLng.lng())
});
map.addOverlay(currentMarker);
dlg.show();
}
}
function markerAddComplete() {
var title = document.getElementById('title');
currentMarker.setTitle(title.value);
title.value = "";
currentMarker = null;
dlg.hide();
}
function cancel() {
dlg.hide();
currentMarker.setMap(null);
currentMarker = null;
return false;
}
</script>
I also greated the variables that will hold the coordinates:
#ManagedBean
#RequestScoped
public class NewOfferSupportController {
private float mapLocationX;
private float mapLocationY;
//Get & set methods
It all works as in the primefaces page but I have 2 problems:
Problem 1: Once the marker is placed, it cannot be placed again.
Problem 2: In the same form where the map is there are some other elements such as text fields. I noticed that validation does not occur when I click on the submit button located in the form where the map is, Actually the form does not get submitted at all(This didn't occur before i added the map), why is the map disrupting the validation?
Problem 1: Once the marker is placed, it cannot be placed again.
This problem is caused by the following things:
You've bound latitude and longitude to a different bean (NewOfferSupportController) than the bean which holds the map model (MapBean). You should be using MapBean example in the PrimeFaces showcase as design starting point for NewOfferSupportController bean. It namely stores the markers set. The hidden inputs must point to that bean because in the addMarker() method those values will be added. From the showcase example you just have to rename the MapBean class name and rename #{mapBean} references in the view by #{newOfferSupportController}.
Your NewOfferSupportController bean is request scoped while it should be view scoped.
#ManagedBean
#ViewScoped
public class NewOfferSupportController implements Serializable {}
View scoped beans live as long as you're interacting with the same form by Ajax. But request scoped beans get recreated on every request (and thus also on every Ajax request!), hereby trashing the markers which are placed before in the map and inputs which are entered before adding markers.
Problem 2: In the same form where the map is there are some other elements such as text fields. Actually the form does not get submitted at all(This didn't occur before i added the map), why is the map disrupting the validation?
This works for me. This is likely caused because your NewOfferSupportController is been placed in the request scope instead of the view scope.
To recap, here is the code which I used in my test:
view:
<p:growl id="messages" showDetail="true" />
<h:form>
<p:gmap id="gmap" center="36.890257,30.707417" zoom="13" type="HYBRID" style="width:600px;height:400px"
model="#{mapBean.mapModel}" onPointClick="handlePointClick(event);" widgetVar="map" />
<h:inputText value="#{mapBean.input}" required="true" />
<p:commandButton value="submit" action="#{mapBean.submit}" update="messages" />
</h:form>
<p:dialog widgetVar="dlg" effect="FADE" effectDuration="0.5" close="false" fixedCenter="true">
<h:form prependId="false">
<h:panelGrid columns="2">
<h:outputLabel for="title" value="Title:" />
<p:inputText id="title" value="#{mapBean.title}" />
<f:facet name="footer">
<p:commandButton value="Add" actionListener="#{mapBean.addMarker}"
update="messages" oncomplete="markerAddComplete()"/>
<p:commandButton value="Cancel" onclick="return cancel()"/>
</f:facet>
</h:panelGrid>
<h:inputHidden id="lat" value="#{mapBean.lat}" />
<h:inputHidden id="lng" value="#{mapBean.lng}" />
</h:form>
</p:dialog>
(I didn't change the <script> code in the showcase example, just add it unchanged)
Bean:
#ManagedBean
#ViewScoped
public class MapBean implements Serializable {
private MapModel mapModel;
private String title;
private double lat;
private double lng;
private String input;
public MapBean() {
mapModel = new DefaultMapModel();
}
public void addMarker(ActionEvent actionEvent) {
mapModel.addOverlay(new Marker(new LatLng(lat, lng), title));
addMessage(new FacesMessage(FacesMessage.SEVERITY_INFO, "Marker Added", "Lat:" + lat + ", Lng:" + lng));
}
public void submit() {
addMessage(new FacesMessage(FacesMessage.SEVERITY_INFO, "Form submitted", "Amount markers: " + mapModel.getMarkers().size() + ", Input: " + input));
}
public void addMessage(FacesMessage message) {
FacesContext.getCurrentInstance().addMessage(null, message);
}
// Getters+setters.
}