JSF2 ajax events not triggered in dynamically included pages - ajax

I have a AdminHome.xhtml page which has a dynamic include as below:
<h:form id="masterform">
<table class="DEFTABLE">
<tbody>
<tr>
<td class="CREATESTYLE">Create
<h:selectOneMenu styleClass="SELECTBOX" id="createBox" value="#{adminWindowController.actionSelection}">
<f:ajax event="change" execute=":masterform:workspace" listener="#{adminWindowController.invokeAction}" render=":masterform:workspace :masterform:taskbar createBox"/>
<f:selectItem itemValue="NONE" itemLabel="Select one..."/>
<f:selectItem itemValue="CREATE_ENTITY_DEFINITION" itemLabel="Entity Definition"/>
<f:selectItem itemValue="CREATE_ENTITY_GROUP" itemLabel="Entity Group" />
<f:selectItem itemValue="CREATE_USER" itemLabel="User" />
<f:selectItem itemValue="CREATE_USER_GROUP" itemLabel="User Group" />
</h:selectOneMenu>
</td>
</tr>
</tbody>
</table>
<h:panelGroup id="workspace">
<table class="DEFTABLE">
<tr>
<td class="WSHEIGHT" valign="top">
<ui:include src="#{adminworkspace.workspaceContent}"/>
</td>
</tr>
</table>
</h:panelGroup>
</h:form>
The above include will get page names dynamically during various ajax events triggered on AdminHome.xhtml page.
Below is one of the dynamic pages that gets loaded when the selectOneMenu changes.
<ui:composition>
<h:form id="entdefcreateform">
<h:panelGroup id="entdefpanel">
<table>
</table>
<table cellspacing="0">
<tr>
<ui:repeat value="#{adminEntityDefnController.entDefTabList}" var="tab">
<td class="#{tab == uIUtil.getRequestMapValue('activetab','General') ? 'TABBUTTONCTIVE' : 'TABBUTTON'} ">
<h:commandLink action="#{adminWindowController.TabChange}" style="border: none;">
<f:ajax execute=":masterform:entdefcreateform:entdefpanel" render=":masterform:entdefcreateform:entdefpanel"/>
<f:param name="activetab" value="#{tab}"/>
<h:outputText value="#{tab}"/>
</h:commandLink>
</td>
</ui:repeat>
</tr>
</table>
<table class="TABCONTENTTABLE">
<tr valign="top">
<td class="TABCONTENT">
<ui:include src= "#{adminEntityDefnController.entDefTabTable.get(uIUtil.getRequestMapValue('activetab','General'))}"/>
</td>
</tr>
</table>
</h:panelGroup>
</h:form>
</ui:composition>

In JSF2, <ui:include>s are evaluated during restore view phase, not during render response phase. Therefore, they do not work dynamically (anymore). I have had the same problem after migrating from JSF 1.2 to 2.1.

I got it working by changing the action method of the bean. The trick is to return to the same page that fires the ajax request. I'm using PrimeFaces 2.2.1 and the menu fires in ajax way.

The first problem i see in your code is that you could NOT have 2 <form> : one nested in another.
I guess that's why your events don't fire.
I had the same problem in may code !
BTW BalusC could you explain more precisely what you did by
"The trick is to return to the same page that fires the ajax request. I'm using PrimeFaces 2.2.1 and the menu fires in ajax way"
This is not clear for Me

E.g. you have <ui:include src="#{bean.value}", where bean is view scope bean.
It is possible to still use dynamic page loading. You can use either of these 2 solutions:
Set javax.faces.PARTIAL_STATE_SAVING to false in web.xml for you project. It will trigger the jsf1.2 way of state saving.
When <ui:include/> evaluates the value - new instance of view scope bean is created and not taken from context. As a result, the default value for src taken. If you put the bean within the session scope (which is not good) or create new session scope bean which will contain only your page path string (to minimize session size), it will resolve the issue.
Here's another tip if you want to reset this session bean value from navigation from page to page. One of the ways is to create fake method "reset()" and put <c:if test="#{bean.reset}"></if> before <ui:include/> to make this initialization for your page. Reset can look like:
private String lastViewId;
public boolean isReset() {
String viewId = FacesContext.getCurrentInstance().getViewRoot().getViewId();
if (!viewId.equals(lastViewId)) {
lastViewId = viewId;
//make any clean here
}
return false;
}

Related

Looking for a away to validate pre-submit in jsf [duplicate]

This question already has answers here:
How to perform JSF validation in actionListener or action method?
(5 answers)
Validate email format and uniqueness against DB
(1 answer)
Closed 2 years ago.
I've run into a problem validating a certain input (email) before submitting the whole object..
jsf looks like this:
<h:panelGroup id="reportingRecipientTable">
<table cellspacing="0" class="table no-footer" width="100%" style="word-wrap: break-word;">
<thead>
<tr>
<th><h:inputText p:type="email" p:placeholder="Add a valid Email address" value="#{viewModel.reportingRecipient}"
styleClass="form-control #{component.valid ? '' : 'has-errors'}">
<f:ajax execute="#this" />
</h:inputText></th>
<th class="col-sm-3">
<div class="text-center">
<h:commandLink immediate="true" style="width:95px" styleClass="btn btn-default" actionListener="#{viewModel.addReportingRecipient}">
<i class="icon-plus" /> Add
<f:ajax render="reportingRecipientTable" />
</h:commandLink>
</div>
</th>
</tr>
</thead>
<tbody>
<c:forEach items="#{viewModel.getReportingRecipients()}" var="reportingRecipient">
<tr>
<td><h:outputText required="true" value="#{reportingRecipient}" styleClass="form-control" /></td>
<td class="col-sm-3">
<div class="text-center">
<h:commandLink styleClass="btn btn-default" style="width:95px" actionListener="#{viewModel.removeReportingRecipient(reportingRecipient)}">
<i class="icon-trash" /> Remove
<f:ajax render="reportingRecipientTable" />
</h:commandLink>
</div>
</td>
</tr>
</c:forEach>
</tbody>
</table>
</h:panelGroup>
As you see, I'm adding a (supposedly valid) email address to a tablerow before submitting everything:
public void addReportingRecipient() {
if (!Utils.isNullOrBlank(reportingRecipient) && reportingRecipient.matches("(^.*#.*\\..*$)")) {
getReportingRecipients().add(reportingRecipient);
this.reportingRecipient = "";
} else{ //not valid
}
}
Well, this works (email is only added if it matches the pattern), missing one little detail: I want to mark the "inputText" as invalid (styleClass="form-control #{component.valid ? '' : 'has-errors'}") if it isnt a valid email address. adding a validator to the inputText like this:
<h:inputText p:placeholder="Add a valid Email address" validator = "#{emailValidator.isCorrectEmail}" value="#{viewModel.reportingRecipient}"
styleClass="form-control #{component.valid ? '' : 'has-errors'}">
does only work if i hit the final submit button - but i want to mark the field invalid the moment the user tries to add an invalid email.
Anyone got an idea/some hints?
Your code example of using a validator is the right way to go. Don't validate in business methods.
<h:inputText p:type="email" p:placeholder="Add a valid Email address" value="#{viewModel.reportingRecipient}"
styleClass="form-control #{component.valid ? '' : 'has-errors'}">
<f:ajax execute="#this" />
</h:inputText></th>
Does correctly use #{component.valid...} to style the component. But it does not work on the ajax call because you do not (re)render the input on the ajax event. The default is for an f:ajax is render="#none", so nothing is updated. Adding a render="#this" or if you also want to display a message some other id will make it work.
The fact that it works on 'Remove' button is because the ajax call on the input has already updated the state and you do render the complete table. So the input is (re)renderd.
See also
Understanding PrimeFaces process/update and JSF f:ajax execute/render attributes
Validator is called but error message is not displayed
Highlight an inputText in JSF when a validation error occurs

JSF PrimeFace: p repeat ajax update with class not working

totalListSumA is an ArrayList inside java. Inside debug mode, the arraylist work just fine. New value assigned into this list.
When user input a new value in a box, program will recalculate new sum and display inside the code shown below.
<p:inputNumber
class="caseType1"
rendered="#{inputFormTemplateView.allowEdit}"
inputStyle="text-align: center"
minValue="0"
maxValue="99999999"
decimalPlaces="0"
thousandSeparator=""
emptyValue=""
value="#{inputFormView.selectedInputFormDetail.data[dataField]}" >
<p:ajax update="dataField, #{inputForm4_1View.getColTotal()}"/>
<p:ajax update="#(.totalRow3)"></p:ajax>
</p:inputNumber>
<tr>
<td align='center'>Total</td>
<p:repeat var="item" value="#{inputForm4_1View.totalListSumA}" class="totalRow3">
<td class="cell_cal" style='text-align:center;' >
<h:outputLabel
class="totalRow3"
value="#{item}" />
</td>
</p:repeat>
</tr>
I have tried
h:panelGroup id='...'
ui:repeat id='....'
Still the value remain unchanged inside p:repeat. Any method I can try to get and show the latest value inside totalListSumA?
This is wrong
<p:ajax update="dataField, #{inputForm4_1View.getColTotal()}"/>
<p:ajax update="#(.totalRow3)"></p:ajax>
1) Ajax should have event="change" or other events, but most wrong thing is that calling bean method inside update.
2) Use listener="#{inputForm4_1View.getColTotal()}"
3) Don't use 2 same ajaxes.
Solution:
<p:ajax event="change" update="dataField, #(.totalRow3)" listener="#{inputForm4_1View.getColTotal()}"/>
If this doesn't solve your problem, try update form like update="#form" or update="yourFormId"

JSF input file tag + ajax

I lost whole day on this issue and got nothing. I know that the question was asked but it was never answered. BalusC said that this issue is fixed in JSF 2.2.5 but either it is not or i do something wrong.
I use h:inputFile tag with ajax to render choosen image in preview div after chosing one from disk. However it's rendered only once and i have to reload page to see next chosen image. It causes more errors. For example when I use SUBMIT button to send chosen image to DB, ajax from commandLink is not executed (image is saved and rendered after page after refresh).
It looks to me like ajax is broken after chosing an image from disk and followed ajax actions are not executed, even they dont belong to h:inputfile.
This is my JSF form (one of its versions because i tried so many tricks)
<h:panelGroup class="photo-update" rendered="#{profileBean.page eq 'photo'}">
Dodaj lub zmień swoje zdjęcie profilowe[...]
<h:form enctype="multipart/form-data">
<h:panelGroup id="form-content">
<h:panelGroup id="current-image" class="current-image">
<p:graphicImage value="#{imageBean.getUserImage()}"/>
</h:panelGroup>
<h:panelGroup id="accept-container-ajax">
<h:panelGroup id="accept-container" class="accept-container"
rendered="true">
<div class="arrow">
<img src="resources/images/arrow.png"/>
<div class="change-text">Zamień na</div>
</div>
<h:panelGroup id="new-image" class="new-image">
<p:graphicImage value="#{profileBean.getConvertedImage()}"/>
</h:panelGroup>
<h:commandLink class="btn btn-default ok-button" value="zatwierdź"
action="#{profileBean.uploadPhoto}">
<f:ajax render="accept-container-ajax current-image"
execute="#form"/>
</h:commandLink>
</h:panelGroup>
</h:panelGroup>
<div class="btn btn-default change-image-container">
Zmień zdjęcie
<h:inputFile immediate="true" id="change-image"
class="change-image" value="#{profileBean.image}">
<f:ajax render="accept-container-ajax" execute="#form"/>
</h:inputFile>
</div>
</h:panelGroup>
</h:form>
</h:panelGroup>
This is fragment of the bean:
public StreamedContent getConvertedImage() throws IOException {
return userBo.convertPartToStream(image);
}
public void uploadPhoto() {
this.renderChangeContainer = false;
if (userBo.addImage(this)) {
FacesContext.getCurrentInstance().addMessage(
null, new FacesMessage(
FacesMessage.SEVERITY_INFO, "...", null));
} else {
FacesContext.getCurrentInstance().addMessage(
null, new FacesMessage(
FacesMessage.SEVERITY_ERROR, "...", null));
}
}
injected BO methods are OK.
Please give me a clue what is going on.
EDIT:
I also see ugly iframe with some response content i guess.

p:pickList not fetching data after pressing p:commandButton

I have a users list page which holds the users in a p:dataTable and in each row I have an update button that shows a p:dialog popup.
The page and the dialog is managed in view scope (implemented in Spring).
When I press the editUserButton in the main page the popup appears with all data and then I type an invalid string into the fields email and username. The validation message appears, but the picklist is not populated with any value.
What could be the problem?
This is the main page (users list) snippet code:
<ui:composition>
<f:view id="bodyView">
<div id="content_body">
<ui:include src="editUserDialog.xhtml"/>
<h:form id="usersListForm">
<table width="85%" align="center">
<tr>
<td>
<p:dataTable id="usersList" var="user"
value="#{usersController.usersList}"
selectionMode="single"
rowKey="#{user.userId}">
<p:columnGroup type="header">
<p:row>
...
<p:column rowspan="2" headerText="Users"/>
...
</p:row>
</p:columnGroup>
...
<p:column id="users" >
<p:commandLink id="editUserButton" oncomplete="addEditUserConfirmation.show()" actionListener="#{addEditUserController.selectionListener}"
update=":addEditCustomerDialogForm:dialogContent">
<f:attribute value="#{user}" name="selectedUser" />
</p:commandLink>
</p:column>
</p:dataTable>
</td>
</tr>
</table>
<br/>
</h:form>
</div>
</f:view>
This is the p:dialog code:
<ui:composition>
<h:form id="addEditUserDialogForm">
<p:dialog id="addEditUserDialog" severity="alert" widgetVar="addEditUserConfirmation" draggable="true" modal="true"
resizable="false" >
<p:outputPanel id="dialogContent">
<div>
<table cellpadding="5">
<tr>
<td>
<p:inputText value="#{addEditUserController.addEditCustomerBean.userName}"
maxlength="250" size="50" label="user name" id="userName">
<f:validator validatorId="UsernameValidator"/>
</p:inputText>
<p:message for="userName"/>
</td>
</tr>
<tr>
<td>
<p:inputText value="#{addEditUserController.addEditCustomerBean.email}"
maxlength="50" size="50" label="E-mail" id="email">
<f:validator validatorId="EmailValidator"/>
</p:inputText>
<p:message for="email"/>
</td>
</tr>
</table>
<table cellpadding="5">
<tr>
<td>
<p:pickList id="customersList" iconOnly="true"
value="#{addEditUserController.customersList}" var="customer"
itemValue="#{customer.value}" itemLabel="#{customer.label}"/>
</td>
</tr>
</table>
</div>
<div align="right">
<p:commandButton value="#{isNewUser ? 'add' : 'update'}" id="updateUserButton"
actionListener="#{addEditUserController.persistUser}"
update="dialogContent"
styleClass="fiftyone-default-button"
oncomplete="handleRequest(xhr, status, args)"/>
</div>
</p:outputPanel>
</p:dialog>
</h:form>
<script type="text/javascript">
function handleRequest(xhr, status, args) {
if(!(args.validationFailed && args.validationFailed == true)) {
addEditUserConfirmation.hide();
}
}
</script>
This is the backing bean code:
import org.primefaces.model.DualListModel;
import javax.annotation.PostConstruct;
import javax.faces.event.ActionEvent;
import java.util.List;
public class AddEditUserController {
private AddEditCustomerBean addEditCustomerBean;
private DualListModel<LabelValueBean> customersList;
// ... constructor getters and setters
public void selectionListener(ActionEvent event) throws Exception {
selectedUser = event.getComponent().getAttributes().get("selectedUser");
// some code
AddEditCustomerBean = new AddEditCustomerBean();
// some code
customersList = getSomeCustomersDualListModel()
}
public void persistUser() throws Exception {
// save user to DB
}
}
First thing I'd do would be to make sure that the method selectionListener is being called (either put a break-point on it or print something and check in the console later).
If it is, you must check if the variable customersList is being updated correctly, if it's not, you probably have a problem with bean scoping.
In your sample code it isn't clear how you are setting the scope for the backing bean, so I assume you're doing it on Spring's XML config file.
Make sure you really have the backing bean in the view scope, by inspecting the contents of the view map: FacesContext.getCurrentInstance().getViewRoot().getViewMap().
Hope it helps!
This is an old question, but I also encountered this issue recently, and now being helpless. Let's see the p:pickList:
<td>
<p:pickList id="customersList" iconOnly="true"
value="#{addEditUserController.customersList}" var="customer"
itemValue="#{customer.value}" itemLabel="#{customer.label}"/>
</td>
We know the [var="customer"] is an iterator, but when validation error happens, this var is assigned to String type, it's odd. When you close this popup then re-populate it again, you will get an error, messages like this: no property label(value) on type of String... the customer var now is a String, so it has no value nor label property.
For now, I use a tricky way, it won't work out always, it depends on your code:
Assume that the value and label are unique, set customersList type of List String, customersList binds the label, find the value of the label when submit at the backend; Why this way can avoid re-populate exception, that's because the iterator is always type of String, no matter validation error occurs or not.
Hope this can help the need.

SelectOneRadio set time on selection

I've been raking my brain trying to figure this one out. I have a really simple requirement that's turning out to be a very interesting problem.
The requirement is to update a time stamp when the user chooses a selection in a radio button list.
So I have a radio button list:
...
<h:selectOneRadio value="#{mybean.myvalue}" >
<f:selectItem itemLabel="A" itemValue="A"/>
<f:selectItem itemLabel="B" itemValue="B"/>
<f:selectItem itemLabel="C" itemValue="C"/>
<f:selectItem itemLabel="D" itemValue="D"/>
<f:ajax render="timeBox" listener="#{measurements.captureTime('timeBox')}"/>
</h:selectOneRadio>
...
And a text box a little further down the page:
...
<h:outputText id="timeBox" value='#{measurements.timeBox}'>
<f:convertDateTime pattern="HH:mm:ss"/>
</h:outputText>
...
And then in the backing bean I have the listener defined:
...
public void captureTime(String id){
if(id.equals("timeBox"){
timeBox = new Date(System.currentTimeMillis());
}
}
...
But when I change the radio button, the value is not updating. I'm pretty sure this is to do with the various phases of JSF (ie. it's not being updated because of the problem in this post: http://balusc.blogspot.ca/2012/03/reset-non-processed-input-components-on.html) but I'm not entirely sure how to fix it.. I'd really like to avoid including another library if possible.
As always let me know if you need more info and I will be happy to oblige.
Thanks!
Edit
The structure of these components is:
<h:form>
<table>
<tr>
<td>
<h:select.../>
</td>
</tr>
<tr>
<td>
<h:output.../>
</td>
</tr>
</table>
</h:form>
The given construct suggests that you've duplicate components with the same ID. Make sure that you don't actually have duplicate components with the same ID.

Resources