submitting form with p:commandButton jsf - jsf

I have a question regarding submitting form content with p:commandbutton that tends to work in the ajax way.
If I have a code like this:
<f:verbatim rendered="#{myBean.constructor}"></f:verbatim >
<h:form prependId="false">
....
.....
<p:commandButton value="#{msg.Add_Parameter_Set}" update="addParameterSetPnl,msgs" action="#{myBean.initNewParametersSet}"/>
</h:form>
When submitting the form with the command button, will the method getContructor from f:verbatim be called (I update different parts of the form)? How can I prevent it from being called?
I thought that submitting a form, only renders the content of the form / the content that was specified by update parameter..

It shouldn't harm. If you're doing expensive stuff in there, then you should move that to the constructor, #PostConstruct or action method of the bean in question, or introduce lazy loading or phase sniffing.
// In Constructor..
public Bean() {
constructed = getItSomehow();
}
// ..or #PostConstruct..
#PostConstruct
public void init() {
constructed = getItSomehow();
}
// ..or action method..
public String submit() {
constructed = getItSomehow();
return "outcome";
}
// ..or lazy loading..
public boolean getConstructed() {
if (constructed == null) constructed = getItSomehow();
return constructed;
}
// ..or phase sniffing (this one updates during render response only).
public boolean getConstructed() {
if (FacesContext.getCurrentInstance().getRenderResponse()) constructed = getItSomehow();
return constructed;
}
See also
Why JSF calls getters multiple times?

Related

Setter of application scoped bean fails to set value

I'm making page using Primefaces with form with ability to ajax-upload image and preview it before submitting whole form.
To achieve this I made dialog outside main form:
<p:dialog id="imageDlg" header="Load Image" modal="true"
widgetVar="imageUploadWidget">
<h:form id="imageForm" enctype="multipart/form-data">
<p:fileUpload mode="advanced" auto="true" sizeLimit="9999999"
allowTypes="/(\.|\/)(gif|jpe?g|png)$/"
fileUploadListener="#{pageBean.imageUploadHandler}">
</p:fileUpload>
</h:form>
</p:dialog>
Inside main form there is p:graphicImage component to display just uploaded image and button to show dialog. Page is backed by view scoped bean (PageBean), but to pass StreamedContent to p:graphicImage value bean should be session or application scoped (because method called multiply times). So I made second application scoped bean (ImageBean) only for this purpose.
<p:graphicImage value="#{imageBean.imageStreamedContent()}"/>
<p:commandButton value="Choose image" type="button"
onclick="imageUploadWidget.show();"/>
Code of ImageBean:
#ApplicationScoped
#ManagedBean
public class ImagesBean implements Serializable {
private byte[] image;
//getter & setter
public StreamedContent imageStreamedContent() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
} else {
return new DefaultStreamedContent(new ByteArrayInputStream(getImage()));
}
}
}
The next part is fileUploadListener. Idea is simple — set corresponding fields of PageBean (to save it later on form submit) of ImageBean (to show it after partial refresh) and update part of main form:
#ManagedBean
#ViewScoped
public class PageBean implements Serializable {
#ManagedProperty(value="#{imageBean}")
ImagesBean imagesBean;
...
public void imageUploadHandler(FileUploadEvent event) {
getImagesBean().setImage(event.getFile().getContents());
RequestContext.getCurrentInstance().update("form:tabPanel1");
}
Here comes strange thing. Inside setImage() method everything is OK - field is set, getter works fine. But then page refresh, imageBean.getImage() inside imageBean.imageStreamedContent() returns null.
More accurate — it returns old value, as if setter was never called or was called on another instance of bean. I checked it on another String field: initialized it in ImageBean constructor, in handler invoked setter with another value and refreshed part of main form. Same thing: old value from constructor.
I think, that I'm missing something about bean life cycle or scope specific. Or maybe there is less complicated way to implement this task?
There is a problem with using StreamedContent in Primefaces for p:graphicImage and p:media.
You can see Cagatay Civici 's comments on this topic in Primefaces forum here.
In my experience, when I had the slimier(more or less) problem This and This answers by BalusC helped me.
I used a saperate Servlet instead of Managedbean to stream the dynamic content to p:media (in mycase).
Here is my code for your reference(if you need any):
PreviewFileServlet.java
#WebServlet("/PreviewFile")
public class PreviewFileServlet extends HttpServlet {
public PreviewFileServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = request.getServletContext();
String path = request.getParameter("PREVIEW_FILE_PATH");
logger.info("Received pathe for Preview:"+path);
try{
if(null!=path){
java.io.File f = new java.io.File(path);
if(f.exists()){
FileInputStream fin = new FileInputStream(f);
byte b[] = new byte[(int)f.length()];
fin.read(b);
response.setContentLength(b.length);
response.setContentType(context.getMimeType(path));
response.getOutputStream().write(b);
response.getOutputStream().close();
logger.info("File sent successfully for Preview.");
}
else{
logger.warn("File sepecified by path:-"+path+"-:, NOT found");
}
}
}catch(Exception e){
}
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
Facelet Code
<p:media value="/PreviewFile?PREVIEW_FILE_PATH=#{fileManager.previewFilePath}" />
Hope this helps.
And there are lot of questions on this topic of StreamedContent in stackoverflow itself, go through them once.

When using lazy dataTable another component does not get updated / 2nd component data is one request behind

I have a PrimeFaces p:dataTable and enabled lazy loading by implementing a LazyDataModel.
The dataTable holds search results, so when doing a search request the search service only retrieves the required (paginating) data. That works fine.
When doing a ajax request with p:commandButton:
<p:commandButton id="searchCmdBtn" value="Search" action="#{searchBean.search}"
update=":resultForm:resultList :filterForm:filterMenu :resultForm:messages"
ajax="true" />
the dataTable gets updated properly, but not the filterMenu in the filterForm (differnt forms, bcz using p:layout).
The filterMenu is one request behind. Which means when I hit search button again, the filterMenu gets updated with t only gets updated after the 2nd ajax request
Bean
#ManagedBean
#ViewScoped
public class SearchBean implements Serializable {
private LazyDataModel<Entity> lazyDataModel;
private MenuModel filterMenuModel = new DefaultMenuModel();
private SearchResult searchResult = null;
public void search() {
// lazy call
getLazyDataModel();
if (searchResult != null) {
buildFilterMenu(searchResult);
}
}
private void initializeDataModel() {
lazyDataModel = new LazyDataModel<Entity>() {
private static final long serialVersionUID = 1L;
#Override
public List<Entity> load(int first, int pageSize, List<SortMeta> multiSortMeta, Map<String, String> filters) {
// handling sorting and filtering
// get search results
try {
setSearchResult(searchService.getEntities(queryText, selectedQueryOperand, getFilterOptions(), first, (first + pageSize), multiSortMeta));
} catch (Exception e) {
// handle exception
}
if (searchResult == null) {
return null;
}
List<Entity> resultEntities = searchResult.getResultEntities();
// total count
this.setRowCount((int) searchResult.getTotalSize());
return resultEntities;
}
// other override-methods
};
}
public void buildFilterMenu() {
// builds the filterMenu depending on searchResults
}
// getters and setters
public LazyDataModel<Entity> getLazyDataModel() {
if (lazyDataModel == null) {
initializeDataModel();
}
return lazyDataModel;
}
}
filters.xhtml
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:p="http://primefaces.org/ui"
xmlns:fn="http://java.sun.com/jsp/jstl/functions">
<p:panelMenu id="filterMenu" model="#{searchBean.filterMenuModel}" />
</ui:composition>
After searching the PF forum I found the root cause:
The dataTable Lazy load() method is invoked during render response phase
To know about the phases, read this tutorial on JSF lifecycle from BalusC
Solutions for displaying messages (e.g: p:messages or p:growl):
Update message component with PrimeFaces RequestContext
RequestContext.getCurrentInstance().update(":growlOrMsgID");
This will not work because at that time it's too late to add additional components to update.
use dataTable attribute errorMessage
No attribute found with this name for dataTable
Put the p:messages or p:growl below the p:dataTable
Worked for me
Use PF execute method of RequestContext
The RequestContext#execute() executes a javascript after current ajax request is completed.
Worked for me
See also:
Request update of component with ajax from LazyDataModel.load?
How to handle error in Primefaces lazy load?
PF Issue: DataTable with LazyDataModel updates model during render
http://itaffinity.wordpress.com/2013/06/08/jsf-displaying-facesmessages-during-render-response-phase/

JSF Reset a property of ViewScoped bean back to initial value after render

I have a ViewScoped ManagedBean. This bean has a boolean attribute which controls whether a datatable should be displayed. See below:
<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">
<p:column>
...
</p:column>
...
</p:dataTable>
My ManagedBean looks like this:
#ManagedBean(name = "loc")
#ViewScoped
public class LocationController implements Serializable {
private boolean renderLocationTable = false;
// JSF ActionListener.
public void methodA() {
if(someCondition) {
renderLocationTable = true; // this is the only time we should render location table
}
}
}
As soon as methodA() gets called and some condition is met, then the table should be rendered; and this works fine. But, the problem is this, for each and every other JSF ActionListener method which gets called, I have to explicitly set the rendered boolean back to false. See below:
#ManagedBean(name = "loc")
#ViewScoped
public class LocationController implements Serializable {
private boolean renderLocationTable = false;
// JSF ActionListener.
public void methodA() {
if(someCondition) {
renderLocationTable = true; // this is the only time we should render location table
}
}
// JSF ActionListener.
public void methodB() {
renderLocationTable = false;
}
// JSF ActionListener.
public void methodC() {
renderLocationTable = false;
}
}
I've given a very small snippet of the actual ManagedBean and XHTML file. In-reality, these files are huge and lot's of stuff is happening with several other boolean "rendered" flags. It is becoming increasingly difficult to keep these flags accurate. Plus, each ActionListener method now has to know about all boolean flags even if they are not related to the business at-hand.
This is what I'd love to be able to do:
<f:event type="postRenderView" listener="#{loc.resetRenderLocationTable}" />
<p:dataTable value="#{loc.locationRows}" var="obj" ... rendered="#{loc.renderLocationTable}">
<p:column>
...
</p:column>
...
</p:dataTable>
Then, in the ManagedBean have a method:
public void resetRenderLocationTable(ComponentSystemEvent event) {
renderLocationTable = false;
}
Wouldn't this be nice? No more playing games with resetting boolean variables. No more test cases where we need to make sure the table doesn't get displayed when it shouldn't be. The rendered flag can be set to true when the appropriate JSF ActionListener method sets it to true and then the "post-back" call will reset the flag back to false...Perfect. BUT, apparently there's no way of doing this out-of-the-box with JSF.
So, does anyone have a solution to this issue?
Thanks!
By the way, this situation happens probably a lot more than you think. Anytime you have a form with several commandButtons using ActionListeners, then this situation could happen to you. If you've ever had a JSF ManagedBean and you find yourself setting boolean flags to true or false scattered through-out the class, then this situation applies to you.
You didn't added primefaces tag, but according to your code I see that you are using Primefaces. A suppose your methodA() is called from, for example p:commandButton. I suggest first to create primefaces remote command:
<p:remoteCommand name="resetRenderLocationTable">
<f:setPropertyActionListener value="#{false}" target="#{loc.renderLocationTable}"/>
</p:remoteCommand>
this will create JavaScript function named resetRenderLocationTable whose call will generate AJAX request which will set renderLocationTable property to false. Now just add call to that function in oncomplete of you commandButton (or any other AJAX source):
<p:commandButton action="#{loc.methodA()}" update="myDatatable" oncomplete="resetRenderLocationTable()"/>
In next request you don't have to worry about resetting this property, just update your datatable.

Validate rich:dataTable value size's on form submit

I have a "new item" form that requires a list of dates, with the following components:
A <rich:calendar> input;
A <a4j:commandButton> that adds the chosen date to a List<Date> chosenDates in the backing bean;
A <rich:dataTable> with it's value set to the List<Date> chosenDates attribute;
A <a4j:commandButton> per dataTable row that removes it's date from theList<Date> chosenDates;
How to validate (JSF's validation phase) the size of the chosenDates list on form submit (creation process)?
RichFaces 4, JSF 2.1 (Mojarra).
I'd advise a cleaner approach with a JSF PhaseListener. The JSF processing will stop skip ahead the other phases if validation fails. Create a PhaseListener that will inspect the size of your list during the validations phase as against during the model update/invoke action phase. Try something like this
Create a phase listener for the validations phase
public class TestPhaseListener implements PhaseListener {
#Override
public void afterPhase(PhaseEvent event) {
throw new UnsupportedOperationException("Not supported yet.");
}
#Override
public void beforePhase(PhaseEvent event) {
if(event.getPhaseId().equals(PhaseId.PROCESS_VALIDATIONS)){
FacesContext ctx = event.getFacesContext();
YourBeanClass theBeanClass = ctx.getApplication().evaluateExpressionGet(ctx, "#{someBean}", YourNeanClass.class); //obtain a reference to the backing bean containing the list
/*
inspect the size of the list here and based on that throw the exception below
*/
throw new ValidatorException(new FacesMessage("Too many dates","Too Many Dates"));
}
}
#Override
public PhaseId getPhaseId() {
throw new UnsupportedOperationException("Not supported yet.");
}
}
Register your new listener in the faces_config.xml file
<lifecycle>
<phase-listener>your.package.structure.TestPhaseListener</phase-listener>
</lifecycle>
EDIT: Based on your comment, as an alternative, you can hook into the component's lifecycle using the <f:event/> tag and the preValidate or postValidate events (depending on your preference)
A listener tag to your component
<rich:dataTable>
<f:event type="preValidate" listener="#{yourBean.listener}"/>
</rich:dataTable>
Define a listener method in your backing bean to run per your defined event. The method signature must take an argument of type ComponentSystemEvent
public void preCheck(ComponentSystemEvent evt){
//You're in your backing bean so you can do pretty much whatever you want. I'd advise you mark the request as validation failed and queue FacesMessages. Obtain a reference to FacesContext and:
facesContext.validationFailed();
}
Do something like:
#{yourBean.chosenDates.size()}
I suppose you have a getter called getChosenDates which returns the chosenDates list.
Regarding your "validation concerns":
You can create a Validate method in your bean and return list of ValidationMessages. A sample is below, one that i used in my code.
public List<ValidationMessage> validate() {
List<ValidationMessage> validations = new ArrayList<ValidationMessage>();
int curSampleSize = sampleTable.getDataModel().getRowCount();
if(getNumberOfSamples() != null) {
size += getNumberOfSamples();
} else {
validations.add(new ValidationMessage("Please enter the no of samples to continue."));
return validations;
}
return validations;
}
Then, on submit you can check if you have any ValidationMessages as follows:
List<ValidationMessage> errs = validate();
if(errs.size()>0) {
FacesValidationUtil.addFacesMessages(errs);
return null;
}
Hope this helps!

Iceface 2.0 commandLink partial submit doesn't work

I have a page which takes in request params for place, then generate information,
for example, http://example.com/xxx/weather.jsf?place=california.
The purpose of doing this is to let user bookmark the link.
In the weather.jsf, there are two outputtext and a commandlink:
Humidity : <ice:outputText value="#{weatherBean.humidity}"/>
Visibility : <ice:outputText value="#{weatherBean.visibility}"/>
<ice:commandLink id="likeButton"
value="Like"
actionListener="#{weatherBean.doLike}" />
In the managedBean:
#ManagedBean(name="weatherBean")
#RequestScoped
public class WeatherBean
{
String humidity;
String visibility;
int numLike;
#PostConstruct
public void init()
{
System.out.println("init called");
HttpServletRequest request= (HttpServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
String place = request.getParameter("place");
setHumidity(WeatherDao.getHumidity(place));
setVisibility(WeatherDao.getVisibility(place));
setNumLike(GeneralDao.getNumLike());
}
public void doLike(ActionEvent event)
{
System.out.println("doLike called");
GeneralDao.addNumberLike();
}
}
Alright, the page generated perfectly.
However, when I click the doLike commandLink,
it always triggers the init method first, then call doLike method.
Since the request param is empty, all the other values reset.
Is there any way to prevent a refresh of the page or calling of init method?
I tried partialsubmit or immediate, but no luck.
Your bean is #RequestScoped, so after executing the JSF lifecycle, your bean instance is lost, until the next request comes in, at which point you get a new instance of your bean, and the PostContruct re-executes.
Try changing the scope of your bean to something longer lived, like #ViewScoped.

Resources