Get SelectOneMenu 's selected item from code - java

I'm trying to get a primefaces SelectOneMenu selected item's name from code:
This is my SelectOneMenu:
FacesContext.getCurrentInstance().getViewRoot().findComponent("formMain:somSelect");
The Component is found.
I already tried to cast it into a SelectOneMenu but I won't get a method like "getSelectedValue()" which is written in the user manual in "client side api".
I also tried:
FacesContext.getCurrentInstance().getViewRoot().findComponent("formMain:somSelect").getAttributes().get("label");
But this returns NPE.
<p:selectOneMenu id="somSelect" value="#{userManagerBean.somValue}" valueChangeListener="#{userManagerBean.somListener}" styleClass="selecters">
<f:selectItems value="#{userSelectBean.userList}" />
</p:selectOneMenu>
UserManagerBean.java
#ManagedBean
#RequestScoped
public class UserManagerBean {
private String somValue;
private String selectedUser;
private List<User> userData;
private List<User> users;
public UserManagerBean() {
}
public String getSomValue(){
return somValue;
}
public void setSomValue(String somValue){
this.somValue = somValue;
}
// Getter for Table Content
public List<User> getUserData() {
return userData;
}
Any ideas?
€: The problem is that the selected item is only returned in the getter if I call a method and an ajax update:
<p:ajax update="panelMain" listener="#{userManagerBean.changeEvent}" />
But I don't get an correct selected item on page load ( item = null ).

As you are using list of beans to populate f:selectItems you should add converter or provide itemValue attribute. In your case as value is String provide itemValue with some String identifier of your User bean:
<f:selectItems value="#{userSelectBean.userList}" var="u" itemValue="#{u.code}" itemLabel="#{u.name}"/>
Change properties code and name to those which you have in your User bean. Be shore that itemValue points to String as your value in backing bean is String.

Related

JSF Java Beans - initialize and proceed

I am new to JavaBeans and I need a little help to keep my first little JSF-project going.
I am writing a little web application where a user can search with certain criteria for buildings. So the user enters in the search form 'location', 'property type', 'asking price', 'number of rooms' and 'living space'.
My managed bean accept the requiry with setter/getter and now the data is to be transmitted to a SQL class, where they are processed and matching search results are returned. It sounds simple, but I can not find a solution.
My managed bean looks like this now:
package beans
//import statements
...
#ManagedBean
#RequestScoped
public class PropertySearchBean {
private String _place
private String _propertyType
private double _askingPrice
private int _rooms
private double _livingSpace
public ArrayList<SearchResults> results = new ArrayList<SearchResults>();
// empty constructor
...
// getter and setter for these 5 user inputs
...
public void initializeSearchResults() {
// do the SQL query, recieve search results
// add it as a new object of 'SearchResults'
SQLPropertySearch search = new SQLPropertySearch(_place, _propertyType,
_askingPrice, _rooms, _livingSpace);
ArrayList<Integer> idResults = search.getPropertyIDlist();
SQLProperty property;
if(!idResults.isEmpty()) {
for(int i=0; i<idResults.size(); i++) {
property = new SQLProperty(idResults.get(i));
results.add(new SearchResults(
property.getPropertyID(),
property.getPropertyName(),
// and so on..
));
}
}
}
public static class SearchResults {
int propertyID;
String propertyName;
// and so on..
public SearchResults(int propertyID, String propertyName) {
this.propertyID = propertyID;
this.propertyName = propertyName;
// and so on..
}
// getter and setter
public int getPropertyID() {
return propertyID;
}
public void setPropertyID(int propertyID) {
this.propertyID = propertyID;
}
// and so on..
}
public ArrayList<SearchResults> getResults() {
return results;
}
}
In my XHTML-file I go through each entry of my ArrayList results.
It looks like this:
<ui:repeat var="res" value="#{PropertySearchBean.results}">
<p>#{res.propertyID}</p>
<p>#{res.propertyName}</p>
</ui:repeat>
I don't have an idea how to initialize the ArrayList, because first thing to do is the search itself, with the user input.
I am thankful for any kind of help!
You've removed the getters and setters from your example to improve readability. I'll provide one implementation here to ensure a common understanding (especially regarding the leading underscores).
public String getPlace() {
return _place;
}
public void setPlace(String place) {
this._place = place;
}
The property 'place' will be accessible within your view by using the value binding #{propertySearchBean.place}(see below).
Your code is meant to perform a search. Therefore you'll have to transfer user input from your XHTML file (view) to your managed bean. To do so you need to add a form to your view. Each search query parameter is bound to your bean using a specific value binding. Additionally the form contains a <h:commandButton> tag which finally triggers initialization of the result list.
<h:form>
<h:outputLabel for="place" value="Place:" />
<h:inputText id="place" value="#{propertySearchBean.place}" />
<!-- Additional fields -->
<h:commandButton action="#{propertySearchBean.initializeSearchResults}"
value="Search"/>
</h:form>
Note: You've used the following code in your example
<ui:repeat var="res" value="#{PropertySearchBean.results}">
Make sure that the first letter of your bean name is lower-case (propertySearchBean instead of PropertySearchBean). So this needs to be updated to
<ui:repeat var="res" value="#{propertySearchBean.results}">

how to access two different java entities as parameters in backing bean method

Mojarra 2.1.5 / Java
I have two entities : i.e.
class Primary { String name; String age }
class Second { String dept; String hour }
...
In my managed bean I developed a function to generate PDF regarding my front-end prime-faces radio button (Primary or Second).
If I select in radio button the Primary option, the managed bean method will fire generatePDF() and inside the generatePDF I have :
Primary pr = new Primary();
pr.name = xxxxx;
pr.age = yyyyy;
...
...
But how can I do to re-utilize the same method generatePDF for both entities (Primary and Second ? I need to access both entity properties regarding my radio selection.
I need to instantiate the entities dynamically (Or I instantiate Primary or I intantiaty Second at a time)
What about do something like this.
interface Pdfeable{ String writeToPDF();}
class Primary implements Pdfeable { String name; String age }
class Second impleaments Pdfeable { String dept; String hour }
Just override with the statements you want to send data to the PDF.
class Primary implements Pdfeable {
String name; String age;
public String writeToPDF(){
return getName() + "" + getAge();
}
}
And write your code using the interface definition not concrete classes.
Assuming as per your question you need one class instantiation at a time as per radio button selection ,I would suggest you should create a valueChangeListener to your radio button.I have hardcoded the values of radio selectItem you can use any way either by bean-binding or hardcoded.
<h:selectOneRadio value="#{myBean.myRadioValue}" ... onclick="this.form.submit();" valueChangeListener="#{myBean.generatePDF}">
<f:selectItem itemValue="Radio1" itemLabel="Primary-radio" />
<f:selectItem itemValue="Radio2" itemLabel="Secondary-radio" />
</h:selectOneRadio>
This code will submit the form where the radio button are contained when the onclick Javascript event is detected. On the server side, the action generatePDF will be executed. In this method, you can do your requiste as on Submit action getter and setter will be called and you can check which radio is selected by comparing using if () and do your stuff:
public void generatePDF(ValueChangeEvent evt) {
if(getMyRadioValue.equals(Radio1)){
Primary pr = new Primary();
pr.name = xxxxx;
pr.age = yyyyy;
}
else if(getMyRadioValue.equals(Radio2)){
Secondary s = new Secondary();
s.dept = xxx;
s.hour = yyyy;}
...
...
}

How to read GET request parameters in JSF from a redirect

I need to get input throug form and put the value in Bean field.
After that I want that by pressing a button Bean action will be triggered and when it finished
I need to move to another page by using href.
I tried this:
<div class="getname">
<h:form>
Enter name
<h:inputText value="#{bean.name}" />
<br/>
</h:form>
<h:commandButton value="Purchase" action="#{bean.sendName}"/>
<a href="name.jsf?id=#{bean.id}" />
</div>
I manage to move to the right name.jsf page (according to the ID) but the action is not triggered.
any ideas?
The commandButton component is what will submit the form values to their managed properties. To do this you must place it inside the <h:form> component.
Furthermore, you do not need a seperate link to navigate away from the page after the action is invoked. A managed bean Action method can return a String which is defines the navigation that FacesServlet will FORWARD to.
#ManagedBean("bean")
public class MyBean {
private String id;
private String name;
/// property accessors and other stuff
public String sendName() {
// do stuff
return "name.jsf?id=" + this.id;
}
}
When the action is complete this return value instructs to navigate you to that defined view.
Command Button and href are both different actions , click on command button will execute action and click on href will take user to the page name.jsf
<h:commandButton value="Purchase" action="#{bean.sendName}"/>
<a href="name.jsf?id=#{bean.id}" />
You need something like this in your bean
#ManagedBean("bean")
public class TestBean {
#ManagedProperty(value = "#{param.id}")
private String id;
private String name;
public String sendName() {
//do stuff
return "name.jsf?id=" + this.id;
}
}
You can also do this in your xhtml to get the same outcome,
<f:metadata>
<f:viewParam name="id" value="#{bean.id}" />
</f:metadata>
Above line will set the parameter id in bean from the request parameter id before your bean is initialized.

Why does Input is holding value after required field validation

When a page is loaded with an input which is bound to a value in the view scopped backing bean and if the value is is pre-initialized, then after required field validation the input is again populated with the previous value.
Here is the managed bean:
#ManagedBean(name = "adminController")
#ViewScoped
public class AdminController extends BaseWebController implements Serializable {
private static final long serialVersionUID = 1019716974557397635L;
private transient CustomerDTO customerDTO;
public AdminController() {
log.debug("Inside AdminController");
}
#PostConstruct
public void init() {
initCustomerDTO();
customerDTO.setCustomerName("Test");
}
public void saveCustomer(ActionEvent event) {
try {
getServiceProvider().getCustomerService().addNewCustomer(customerDTO);
getFacesContext().addMessage(null, FacesMessageUtils.getMessageForCustomerSaveSuccess(getFacesContext()));
} catch (Throwable throwable) {
getFacesContext().addMessage(null, FacesMessageUtils.getMessageForCustomerSaveError(getFacesContext()));
printStackTrace(throwable);
}
initCustomerDTO();
}
private void initCustomerDTO() {
customerDTO = new CustomerDTO();
}
public CustomerDTO getCustomerDTO() {
return customerDTO;
}
public void setCustomerDTO(CustomerDTO customerDTO) {
this.customerDTO = customerDTO;
}
}
CustomerDTO is a POJO.
The jsf contains:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:pe="http://primefaces.org/ui/extensions">
<h:form id="customerForm">
<p:inputText id="customerName" styleClass="customerName"
autocomplete="off"
label="#{adbBundle['admin.addCustomerPanel.addCustomerTable.customerName']}"
value="#{adminController.customerDTO.customerName}"
required="true" />
<p:commandButton value="#{adbBundle['saveButton']}"
actionListener="#{adminController.saveCustomer}"
icon="ui-icon-check"
update=":growl, #form, :adminTabView:customerListForm:customerListPanel" />
</h:form>
</ui:composition>
I also have a custom converter class for trimming blank String.
#FacesConverter(forClass = String.class)
public class StringTrimmer implements Converter {
#Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (StringUtils.isBlank(value)) {
if (component instanceof EditableValueHolder) {
((EditableValueHolder) component).setSubmittedValue(null);
}
return null;
}
return value;
}
#Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
return value.toString();
}
}
So when the page is first loaded the input field contains "Test". I cleaned out the test field and click on the save button. I received error message for required field validation, but the input is again get populated with the default value "Test" that I have set before.
How can I solve the issue?
Update:
I am running in JBoss AS7 with Mojarra 2.1.7, which is JBoss'es implementation and Primefaces 3.4.2.
Your problem is caused by the converter.
When JSF validation fails for a specific component, the submitted value is kept in the component, else it is nulled out and set as local value. When JSF is finished with validation of all components and no one has failed validation, then all local values are nulled out and set as model value (the one referenced as value attribute). When JSF needs to redisplay the form with values, it first checks if the submitted value is not null and then display it, else it checks if the local value is not null and then display it, else it displays the model value outright.
In your case, you're converting the empty string submitted value to null regardless of validation outcome. So the submitted value is always null and thus JSF will always redisplay the model value instead of the empty string submitted value.
I believe that you rather need the following context parameter instead of the converter, certainly if the sole goal is to prevent the model values being polluted with empty strings when empty inputs are submitted.
<context-param>
<param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
<param-value>true</param-value>
</context-param>
Or if your sole goal is really to trim whitespace from string, as the converter class name suggests, then you should not be touching the submitted value at all. You can find a concrete example here: Why does <h:inputText required="true"> allow blank spaces? The getAsObject() won't be set as submitted value, but instead as local value (on validation success) and ultimately as model value.

How can I create a reusable view using JSF

Here is the scenario - I want to create a view which can be used from a number of other views to create and edit a specific type of object.
My application has an address entity which can be shared between other entities.
In the view which maintains an entity, I would like a button/link which navigates to the address edit view for the address linked to that entity.
Another view which handles a different entity also needs to be able to navigate to the address edit view with its address.
The address view would then navigate back to the calling view once editing is completed.
My problem is that I can't seem to find a way to pass the address entity from the first view into the address view.
I think I want some kind of conversation scope, but don't know how to get the address without knowing about the page bean that references it, but obviously my address view can only know about addresses.
I am using JSF2.1 (MyFaces/PrimeFaces) and CDI (OpenWebBeans) and CODI.
I'm sure I must be missing something simple. (Simple relative to JSF/CDI terms that is!)
Just pass the address ID as request parameter and have the target view to convert, validate and set it in the bean by <f:viewParam>.
E.g.
<h:link value="Edit address" outcome="addresses/edit">
<f:param name="id" value="#{address.id}" />
</h:link>
and then in addresses/edit.xhtml
<f:metadata>
<f:viewParam id="id" name="id" value="#{editAddressBacking.address}"
converter="#{addressConverter}" converterMessage="Bad request. Unknown address."
required="true" requiredMessage="Bad request. Please use a link from within the system." />
</f:metadata>
<h:message for="id" />
<h:form rendered="#{not empty editAddressBacking.address}">
<h:inputText value="#{editAddressBacking.address.street}" />
...
</h:form>
In order to navigate back to the original page, you could pass another request parameter.
<h:link value="Edit address" outcome="addresses/edit">
<f:param name="id" value="#{address.id}" />
<f:param name="from" value="#{view.viewId}" />
</h:link>
(where #{view} is the implicit object referring to the current UIViewRoot)
and set it by <f:viewParam> as well so that you can in the submit method of the edit address backing bean just return to it:
public String save() {
// ...
return from + "?faces-redirect=true";
}
See also:
Communication in JSF 2 - Processing GET request parameters
I think I have come up with a solution.
As I am using CODI I can leverage the ConversationGroup annotation.
I've created an emtpy interface AddressConversation, then added this to all the backing beans that need to show the address/addressEdit.xhtml view, as well as the backing bean for the addressEdit view.
I'm also using CODI view config so my action methods return ViewConfig derived class objects.
#Named
#ConversationScoped
#ConversationGroup(AddressConversation.class)
public class AddressView implements Serializable
{
private Class<? extends Views> fromView;
private Address editAddress;
private Address returnAddress;
// Getters/setters etc...
public Class<? extends Views> cancelEdit()
{
returnAddress = null;
return fromView;
}
}
So in a calling view I have (PrimeFaces commandLink)
<p:commandLink value="#{enquiryView.addressLinkText}" action="#{enquiryView.editAddress()}" immediate="true"/>
and in the backing bean EnquiryView I can #Inject an instance of AddressView in the correct conversation group, then set the address and return view properties when action method is called.
#Named
#ConversationScoped
#ConversationGroup(AddressConversation.class)
public class EnquiryView implements Serializable
{
#Inject #ConversationGroup(AddressConversation.class) private AddressView addrView;
public Class<? extends Views> editAddress()
{
addrView.setAddress(editEnq.getAddress());
addrView.setFromView(Views.Enquiry.EnquiryEdit.class);
return Views.Address.AddressEdit.class;
}
}
I can also observe the navigation in EnquiryView and update the enquiry entity when an address has been "saved" in the address edit view.
protected void onViewConfigNav(#Observes PreViewConfigNavigateEvent navigateEvent)
{
if (navigateEvent.getFromView() == Views.Address.AddressEdit.class &&
navigateEvent.getToView() == Views.Enquiry.EnquiryEdit.class)
{
onEditAddressReturn();
}
}
private void onEditAddressReturn()
{
if (addrView.getReturnAddress() != null) {
// Save pressed
editEnq.setAddress(addrView.getReturnAddress());
}
}
If you want another entity to be set when the address is OK, just give the adresss process the EL name of the bean you want to set :
<f:param name="targetBeanSetter" value="enquiryBean.adress" />
And in Java :
public String executeAndBack() {
int last = this.targetBeanSetter.lastIndexOf('.');
String base = this.targetBeanSetter.substring(0, last);
String property = this.targetBeanSetter.substring(last + 1);
Object yourEntityToSet = FacesContext.getCurrentInstance().getELContext().getELResolver().getValue(context.getELContext(), null, base);
try {
PropertyUtils.setSimpleProperty(yourEntityToSet, property, constructeurHolder.getConstructeur());
} catch (Throwable e) {
throw new RuntimeException(e.getMessage());
}
return from + "?faces-redirect=true";
}
If you only need access to the choosen Adress, without building linked objects, when you are back on the first page, just inject in EnquiryView using
#ManagedProperty(value="{address}")
Address adress;

Categories