my intention is to create a form that can query database and return the results of type List. The result should be return inside the same form
that will create commandlink specific to each record in the database result.
However when I try to follow the link generated I am getting the same page and the response is the same even after I applied navigation rules using the faces-config.
All my views are in html5 and using JSF name space. There are no explicit AJAX
request being used in my views.
I am not sure what I am doing wrong.
//JSF Managed Bean
//Filename :Index.java
#Named
#RequestScoped
public class Index implements Serializable {
private static final long serialVersionUID = -1234567890090L;
public String actionFindLink(){
return "review";
}
public List getFindRequests(){
// Return Database result base on values from form submission of type List.
}
}
client template snippet https://www.paste.org/flat/112063
<c:forEach var="req" items="#{index.findRequests}">
<tr>
<td><a jsf:action="#{index.actionFindLink()}" jsf:value="#{req.name}" >
<f:attribute name="rid" value="#{req.id}" />
<f:param name="rid" value="#{req.id}"/></a></td>
<td>${req.claim}</td><td>${req.response}</td></tr>
</c:forEach>
<c:if test="#{empty index.findRequests eq true}">
<tr><td>No Results</td></tr></tr></c:if>
Related
I have bilateral One to Many Relationship in a JSF + JPA application. I want to list out only filtered items from the list in the view. Doing it in the controller is difficult and is it possible to filted like below?
<p:selectOneListbox id="cmbField" value="#{investigationItemController.current}" >
<f:selectItems value="#{investigationItemController.currentInvestigation.reportItems}" var="ri" itemLabel="#{ri.name}" itemValue="#{ri}" itemRendered="#{ri.retired ne true and ri.ixItemType eq 'Value'}" />
</p:selectOneListbox>
As itemRendered is not an attribute, I tried this, but failed.
<p:selectOneListbox id="cmbField" value="#{investigationItemController.current}" >
<ui:repeat value="#{investigationItemController.currentInvestigation.reportItems}" var="ri" >
<h:panelGroup rendered="#{ri.retired ne true and ri.ixItemType eq 'Value'}" >
<f:selectItem itemLabel="#{ri.name}" itemValue="#{ri}" />
</h:panelGroup>
</ui:repeat>
</p:selectOneListbox>
Owner Entity is as below.
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class InvestigationItem extends ReportItem implements Serializable {
private static final long serialVersionUID = 1L;
#OneToMany(mappedBy = "investigationItem", cascade= CascadeType.ALL)
List<InvestigationItemValue> investigationItemValues;
public List<InvestigationItemValue> getInvestigationItemValues() {
return investigationItemValues;
}
public void setInvestigationItemValues(List<InvestigationItemValue> investigationItemValues) {
this.investigationItemValues = investigationItemValues;
}
}
The other entity is as follow
#Entity
public class InvestigationItemValue implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
private InvestigationItem investigationItem;
private String name;
//Getters and setters and some other fields
}
The important code set of the controller class is as follows
#ManagedBean
#SessionScoped
public final class InvestigationItemController implements Serializable {
private static final long serialVersionUID = 1L;
#EJB
private InvestigationItemFacade ejbFacade;
private InvestigationItem current;
private Investigation currentInvestigation;
// Other code goes here
}
How can I filter items when using f:selectItem or f:selectItems in JSF/Primefaces ?
(I will explain my real world situation why I desperately need this functionality.
I am developing a medical applications and terms are confusing. A test or an Investigation (like Full Blood Count or Urine Full Report) can have several properties. Test is represented as an Investigation Entity. A test comprised of one or more fields (like Haemoglobin, White Cell Count for FBC and Colour, Apperance for UFR). It is represented as InvestigationItem. A single InvestigationItem may have a list of possible values of which one is selected for in different occasions. They are identified as InvestigationItemValue. So one InvestigationItem has a list of InvestigationItemValue(s). But some of the InvestigationItemValues may be of string type while others are of numeric, for example. The user needs to select one InvestigationItemValue when designing a new investigation of one particular type. So filtering is needed in the view.)
The PrimeFaces <p:selectOneListbox> actually hides the <select><option> and generates a <div><ul><li> which allows you much more CSS styling freedom.
You can just make use of itemDisabled attribute and then use CSS to set disabled items to display: none.
<p:selectOneListbox ...>
<f:selectItems value="#{investigationItemController.currentInvestigation.reportItems}"
var="ri" itemLabel="#{ri.name}" itemValue="#{ri}"
itemDisabled="#{not ri.retired and ri.ixItemType eq 'Value'}" />
</p:selectOneListbox>
with this CSS
.ui-selectlistbox-item.ui-state-disabled {
display: none;
}
As to your failed attempt with <ui:repeat>; it failed because the <f:selectItem> is evaluated during view build time, not during view render time. However, the <ui:repeat> runs during view render time. During that moment the <f:selectItem> is nowhere available in the component tree. It's supposed to be attached to an UISelectOne/UISelectMany parent during view build time.
JSTL runs during view build time, like <f:selectItem>, so using JSTL <c:forEach> for the loop and <c:if> for the conditional building (not rendering!) should do it as well:
<p:selectOneListbox ...>
<c:forEach items="#{investigationItemController.currentInvestigation.reportItems}" var="ri">
<c:if test="#{not ri.retired and ri.ixItemType eq 'Value'}">
<f:selectItem itemLabel="#{ri.name}" itemValue="#{ri}" />
</c:if>
</c:forEach>
</p:selectOneListbox>
You only need to take into account that this breaks view scoped beans when using a Mojarra version older than 2.1.18.
See also:
JSTL in JSF2 Facelets... makes sense?
I want to process this form (valueChangueListener is not valid in real case).
This is the back bean:
public class TestBean extends PrivateBaseBean implements Serializable {
private List<String> strings;
#PostConstruct
public void init() {
strings = new ArrayList<String>();
strings.add("");
strings.add("");
strings.add("");
}
public void saveAction(ActionEvent event) {
StringBuilder textToShowInMessage = new StringBuilder();
for (String string : strings) {
textToShowInMessage.append(string);
textToShowInMessage.append("; ");
}
FacesMessage msg = new FacesMessage(super.getBundle().getString(
textToShowInMessage.toString()), "");
FacesContext.getCurrentInstance().addMessage(null, msg);
}
getters... setters...
An the view:
....
<h:form>
<ui:repeat var="string" value="#{testBean.strings}">
<h:inputText value="#{string}" />
<br />
</ui:repeat>
<p:commandButton value="#{msg.save}"
actionListener="#{testBean.saveAction}" icon="ui-icon-disk"
update="#form" />
</h:form>
...
When the form is processed in the back bean string list always is blank.
How to process form intput's inside iteration, without any value changue listener?
There are some screenshots:
The same problem occurs with action or actionListener on
Your problem is not connected with PrimeFaces <p:commandButton>'s behaviour, but rather with a scoping problem that is implicilty created when using the <ui:repeat> tag.
First of all, let's depart from your example. Basically, you've got
<ui:repeat value="#{bean.strings}" var="s">
<h:inputText value="#{s}"/>
</ui:repeat>
with the backing List<String> strings.
The culprit is here: value="#{s}". The exported by <ui:repeat> variable s is visible only within its loop and it is not bound to any managed bean's property, but instead only to a local variable. Put it differently, s is not bound/equal to bean.strings[index] as one would expect and has no knowledge, as we see, where it originated from. So basically, you're off with a unilateral relationship: value from the bean is printed in your input properly, but the reverse is not happening.
The workarounds
Workaround #1: wrapper classes / model objects
The situation can be overcome by using a wrapper object for your class. In case of a string it could be a 'simple mutable string', like below:
public class MString {
private String string;//getter+setter+constructor
}
In this case the iteration will be working as predicted:
<ui:repeat value="#{bean.mstrings}" var="ms">
<h:inputText value="#{ms.string}"/>
</ui:repeat>
with the backing List<MString> mstrings.
Note that if you have your model class, like User, and will change its properties within <ui:repeat> the class itself will be effectively a wrapper, so that the properties will be set appropriately.
Workaround #2: chained property access
Another workaround consists of accessing an element of your collection directly from within a <h:inputText> tag. This way, any such property will be set by accessing the bean, then collection, then setting the property at the desired index. Excessively long, but that's how it is. As to the how question, <ui:repeat> provides for an exported current iteration status variable, varStatus, that will be used to access the array/collection in the managed bean.
In this case the iteration will also be working as predicted:
<ui:repeat value="#{bean.strings}" var="s" varStatus="status">
<h:inputText value="#{bean.strings[status.index]}"/>
</ui:repeat>
with the ordinary backing List<String> strings.
My workaround solution take the value directly from the page:
<ui:repeat id="repeat" value="#{bean.strings}" var="s" varStatus="status">
<h:inputText id="x" value="#{s.field}"/>
<h:commandLink style="margin: .5em 0" styleClass="commandLink" actionListener="#{bean.save(status.index)}" value="#{bundle.Send}"/>
</ui:repeat>
The save method:
public void save(String rowid) {
String jsParam = Util.getJsParam("repeat:" + rowid + ":x");
System.out.println("jsParam: " + jsParam); //persist...
}
The getJsParam method:
public static String getJsParam(String paramName) {
javax.faces.context.FacesContext jsf = javax.faces.context.FacesContext.getCurrentInstance();
Map<String, String> requestParameterMap = jsf.getExternalContext().getRequestParameterMap();
String paramValue = requestParameterMap.get(paramName);
if (paramValue != null) {
paramValue = paramValue.trim();
if (paramValue.length() == 0) {
paramValue = null;
}
}
return paramValue;
}
This question already has answers here:
How to ajax-refresh dynamic include content by navigation menu? (JSF SPA)
(3 answers)
Closed 1 year ago.
I'm relatively new to JSF and trying to learn how current JSF 2 applications are designed. I've seen reference to single page applications that use ajax. Can someone fill me in on some of the techniques used and / or point me to a model or book? The books I've seen (JSF Complete Reference etc.) are good for basic tech issues but I can't find a source for current design techniques.
Thanks
Dave
In order to implement your Single Page Application, you should state which piece of your page should be rendered. This can be accomplished making use of a boolean flag such as create, edit, list, and so on. For instance, see the following (Just relevant code)
<h:body>
<h:form rendered="#{userController.stateManager.create}">
<h:panelGroup rendered="#{not empty facesContext.messageList or userController.stateManager.failure}">
<!--render error message right here-->
</h:panelGroup>
<div>
<label>#{messages['br.com.spa.domain.model.User.name']}</label>
<h:inputText value="#{user.name}"/>
</div>
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
</form>
</h:body>
Notice that our form will be rendered when a flag create is true - See second line above. To wrap our flags, we create a classe named StateManager as follows
/**
* I am using lombok, which takes care of generating our getters and setters. For more info, please refer http://projectlombok.org/features/index.html
*/
#Setter #Getter
public class StateManager {
private boolean create;
private boolean edit;
private boolean list;
}
Now, because we are using only a single page, we should use a ViewScoped managed bean, which keep our managed bean scoped active as long as you are on the same view - Is it a single page application, right ? So, no navigation. With this in mind, let's create our managed bean.
#ManagedBean
#ViewScoped
public class UserController implements StateManagerAwareManagedBean {
private #Inject UserService service;
private #Getter #Setter stateManager = new StateManager();
private #Getter #Setter List<User> userList = new ArrayList<User>();
private #Getter #Setter User user;
#PostConstruct
public void initialize() {
list();
}
public void create() {
service.persist(user);
stateManager.setCreate(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void edit() {
service.merge(user);
stateManager.setEdit(false);
stateManager.setList(true);
stateManager.setSuccess(true);
}
public void list() {
userList = service.list();
stateManager.setList(true);
}
}
For each action method, we define which piece of our page should be rendered. For instance, consider that our form was processed, covering all of JSF lyfecycle, which implies that their values was successfully converted and validated, and our action method invoked. By using as example our create action method - see above -, we set its create flag as false because our form was converted and validated, so we do not need to show it again (Unless you want). Furthermore, we set both list and success flag as true, which indicates that the list of our page should be rendered and our form was successfully processed - You could use this flag to show something like "User created" such as bellow
<h:panelGroup rendered="#{userController.stateManager.success}">
#{messages['default.created.message']}
</h:panelGroup>
Now, let's discuss which piece of our page should be rendered when it is called for the first time. Maybe you do not know but a void method annotated with #PostConstruct will be called first. So we define which piece of our page should be rendered. In our example, we call list method, which sets its list flag as true and populate a backing list.
#PostConstruct
public void initialize() {
list();
}
Finally, let's review the following order nested within h:commandButton
<h:commandButton action="#{userController.create}">
<f:ajax execute="#form" render="#all"/>
<f:actionListener type="br.com.spa.web.faces.listener.StateManagerActionListener" />
<f:setPropertyActionListener target="#{userController.stateManager.create}" value="true"/>
<f:setPropertyActionListener target="#{userController.user}" value="#{user}" />
</h:commandButton>
First of all, you should call an ActionListener - here called StateManagerActionListener - which takes care of resetting any StateManager - code bellow. It must be called first before any other setPropertyActionListener designed to control any flag because the order defined within h:commandButton is the order in which they will be called. keep this in mind.
public class StateManagerActionListener implements ActionListener {
public void processAction(ActionEvent e) throws AbortProcessingException {
Map<String,Object> viewMap = FacesContext.getCurrentInstance().getViewRoot().getViewMap();
for(Map.Entry<String,Object> entry: viewMap.entrySet()) {
if(entry.getValue() instanceof StateManagerAwareManagedBean) {
((StateManagerAwareManagedBean) entry.getValue()).setStateManager(new StateManager());
}
}
}
}
StateManagerAwareManagedBean - used in our ViewScoped Managed bean -, which allows that we reset any StateManager of any ManagedBean instead of resetting one by one in our ActionListener, is defined as follows
public interface StateManagerAwareManagedBean {
StateManager getStateManager();
void setStateManager(StateManager stateManager);
}
Second, after defining our ActionListener, we use a setPropertyActionListener which set the flag which controls the enclosing piece of the view as true. It is needed because our form is supposed to be not converted and validated. So, in our action method, we set this flag as false as discussed before.
A couple of notes
User is marked as a RequestScoped ManagedBean so that it can not be injected into a ViewScoped one using a ManagedProperty because its scope is shother. To overcome this issue, i set its value by using a <f:setPropertyActionListener target="#{userController.user}" value="#{user}"> - See our form
Our example use JEE features which need a proper Application Server. For more info, refer http://docs.oracle.com/javaee/6/tutorial/doc/
ManagedBean can play different roles such as a Controller, DTO and so on. When it play a role of a Controller, i prefer suffix its name with Controller. For more info, refer http://java.dzone.com/articles/making-distinctions-between
I have a managed bean under ViewScope. It has an instance variable inside it.
MetaData object has a inputItem object List.
#ManagedBean
#ViewScoped
public class ConBean implements Serializable {
private MetaData metadata;
#PostConstruct
#SuppressWarnings("unchecked")
public void init() throws IOException {
this.metadata = new MetaData ();
}
public void proc(){
List<InputItem> inputs= new ArrayList<InputItem>();
inputs.add(***** code to populate the inputItem List);
//after populating, inputs added to the metadata
metadata.setInputs(inputs);
}
//getters & setters
}
in my JSF , input list is populated inside a UI repeat.
<div id="inputplaceholder">
<ui:repeat value="#{conBean.metaData.inputs}" var="content">
</ui:repeat>
</div>
the div inputplaceholder is periodically updated using a richfaces poll.
<a4j:poll id="poll" interval="12000" action="#{conBean.proc}"
execute="#form" render="inputplaceholder"/>
The problem that I have is even though inputItems are set to the metaData object correctly inside the proc() method, when the view is rendered/partially updated, it doesn't get highlighted in the UI. so partial update takes no effect. I tried moving
this.metadata = new MetaData ();
inside the proc method but had no luck.
any ideas and help is highly appreciated.
thanks ...
Did the partial render really take place? This is impossible. There is namely no JSF component with the ID inputplaceholder. You assigned it to a plain HTML <div> element. Replace it by a fullworthy JSF component:
<h:panelGroup layout="block" id="inputplaceholder">
Also, since you used a relative ID in the render attribute, it will only scan for components in the same parent naming container component. The <ui:repeat> is such one, however the component with the desired ID is placed outside it. You'd like to use an absolute ID instead. Assuming that it's inside a <h:form> with a fixed ID:
<h:form id="myform">
<h:panelGroup layout="block" id="inputplaceholder">
...
then you should be referencing it in the render attribute as follows
render=":myform:inputplaceholder"
can some one help me with the following JSF dataTable? here I am getting data from database table and I used dataTable binding, but I don't know why it displays the rows 3 times in the screen, but if I remove the binding then it displays only one time.
<h:dataTable binding="#{threadController.dataTable}" var="category" value="#{threadController.queryCategories}" border="1" cellpadding="2" cellspacing="0">
<h:column>
<img src="../../images/directory.jpg" alt="Forum Icon" />
</h:column>
<h:column>
<h:form>
<h:commandLink value="#{category.cname}" action="#{threadController.categoryDateItem}" />
</h:form>
</h:column>
// defined globally
private HtmlDataTable dataTable;
private HtmlInputHidden dataItemId = new HtmlInputHidden();
public String categoryDateItem() {
category = (Category) dataTable.getRowData();
System.out.println("category action by select: "+category.getCname());
dataItemId.setValue(category.getId());
return "editItem"; // Navigation case.
}
#SuppressWarnings("unchecked")
public ArrayList<Category> getQueryCategories(){
return (ArrayList<Category>)HibernateUtil.getSession().createCriteria(Category.class).list();
}
output:
myText myText myText
The binding expression to bind this component to the bean value="#{threadController.queryCategories}".So value attribute is sufficient to retrieve data using dataTable tag.
Binding = component backing bean
Value= data model backing bean
So, you have the Value and Binding set correctly (at least, as far as I can see). Your problem may result from the fact that you're not caching the list you're getting back from the database in getQueryCategories().
You really can't have any idea how often getQueryCategories() will be called in the process of rendering that dataTable, so it's a good idea to do something like this:
// Somewhere near the top of the handler class.. create a cache variable:
private ArrayList<Category> qCategories = null;
// now for getQueryCategories
public ArrayList<Category> getQueryCategories(){
if ( qCategories == null ) { // qCategories should be a member of the handler
qCategories = (ArrayList<Category>)HibernateUtil.getSession().createCriteria(Category.class).list();
}
return qCategories
}
This kind of cache-ing is very helpful in JSF apps with handlers that are session of even request scoped, as again you can't really know how often JSF will evaluate your "value" expression in the dataTable.