I am automatically selecting a value for radio button when the user types something in an input text using ajax.
The problem is: when the user types something in the input text and directly submits the form by clicking Get, the form does not submit but only the ajax is called because of the change event and the radio is updated.
A second click on the Get button, submits the form.
I also do not want to use keyup since it migth disturb the user while typing.
I use primefaces 5.1
here is my code:
<h:form id="myForm">
<p:selectOneRadio
value="#{myBean.include}" id="IncludeRadio">
<f:selectItem itemValue="Include" itemLabel="Include" />
<f:selectItem itemValue="Exclude" itemLabel="Exclude" />
<p:ajax process="#this" update="#form" />
</p:selectOneRadio>
<p:radioButton id="IncludeRadio0" for="IncludeRadio" itemIndex="0"/>
<p:radioButton id="IncludeRadio1" for="IncludeRadio" itemIndex="1"/>
<p:inputText
value="#{myBean.fieldValue}"
id="FieldValueInputText">
<p:ajax process="#this" update="#form" />
</p:inputText>
<p:commandButton id="GetButton"
action="#{myBean.execute}"
value="Get">
</p:commandButton>
</h:form>
and the bean:
#ManagedBean
#SessionScoped
public class MyBean {
public void setFieldValue(final String fieldValue) {
if (fieldValue != null && !fieldValue.trim().isEmpty()) {
if (!"Include".equals(getInclude())
&& !"Exclude".equals(getInclude())) {
setInclude("include");
}
} else {
setInclude("");
}
}
public void setInclude(String include) {
this.include = include;
}
public String getInclude() {
return this.include;
}
public void execute() {
// do something
}
}
submit button does not submit but only triggers InputText's onChange event
That happened because the blur event of the input field ajax-updates the submit button around the moment you click it. This way the JavaScript/Ajax logic associated with submit button is not guaranteed to work anymore, because the source element is removed from the DOM.
Make sure that you don't cover the submit button in the ajax update.
Instead of updating the entire form,
<p:ajax ... update="#form" />
update only the pieces which really need to be updated, which are only the inputs in your specific case:
<p:ajax ... update="IncludeRadio FieldValueInputText" />
Or if you'd rather like to not keep track of all those IDs when you have many inputs, grab PFS:
<p:ajax ... update="#(#myForm :input)" />
Related
I got an issue for a while and I can't get rid of it. In my data table I have a column with a button to display a dialog with further information on click.
When I click the first time on the button the dialog opens with the right values, but when I click a second time on button of the same row or any other the values aren't displayed because my event handler findStfPack receive a null value attribute.
I tried to pass the PackageData object to be displayed directly to the method as parameter:
<p:column width="60">
<p:commandButton oncomplete="PF('dlgViewStfPack').show()"
update="search:dlgViewStfPackId"
value=""
title="#{msg['button.search']}"
action="#{budgetViewFulfiledController.findStfPack(_item.stfPack)}"
process="#this"/>
</p:column>
Handler method in view controller:
public void findStfPack(PackageData event){
System.out.println("event: "+event.getPackId());
stfPack= event;
}
Or with primefaces action event:
<p:column width="60">
<p:commandButton oncomplete="PF('dlgViewStfPack').show()"
update="search:dlgViewStfPackId"
value=""
title="#{msg['button.search']}"
actionListener="#{budgetViewFulfiledController.findStfPack}"
process="#this">
<f:attribute name="pack" value="#{_item.stfPack}"/>
</p:commandButton>
</p:column>
Handler method in view controller:
public void findStfPack(ActionEvent event){
PackageData packageData= (PackageData)event.getComponent().getAttributes().get("pack");
System.out.println("event: "+packageData.getPackId());
stfPack= packageData;
}
The dialog:
<p:dialog id="dlgViewStfPackId"
header="#{budgetViewFulfiledController.stfPack.staff.stfName} - Package salarial"
modal="true"
widgetVar="dlgViewStfPack">
<div class="groupDataBox">
<my:outputCurrentPackage currPack="#{budgetViewFulfiledController.stfPack}"/>
</div>
</p:dialog>
And the outcome is the same in the 2 scenarios: on the first event trigger the value is properly passed and displayed but on the second event trigger I got a NullPointerException.
I should specify that, I don't know why but without the update="search:dlgViewStfPackId" the values are not displayed in the dialog.
I don't know exactly the reason, but if you don't update dialog, data can't refresh, it's will be cached the last result.
Try to change like this :
XHMTL
<p:column width="60">
<p:commandButton oncomplete="PF('dlgViewStfPack').show()"
update="#([$id=dlgViewStfPackId])"
value=""
title="#{msg['button.search']}"
action="#{budgetViewFulfiledController.findStfPack(_item.stfPack)}"
process="#this">
</p:commandButton>
</p:column>
JAVA
public void findStfPack(PackageData pd){
System.out.println("event: "+pd.getPackId());
this.stfPack= pd;
}
If it's not working, try to process ID_TABLE
In normal circumstances like this:
<h:form>
<h:selectOneRadio value="#{bean.gender}">
<f:selectItem itemValue="Male" itemLabel="Male" />
<f:selectItem itemValue="Female" itemLabel="Female" />
<f:selectItem itemValue="Other" itemLabel="Other" />
</h:selectOneRadio>
<h:commandButton value="Submit" action="#{bean.action}" />
</h:form>
Selecting one radio button disselects the other & the radio button will be remain selected on the postback. (when the same view is rendered)
However, when we're dealing with an iterating component like <h:dataTable>, the selection is lost.
Consider the snippet:
<h:form id="hashMapFormId">
<b>HASH MAP:</b>
<h:dataTable value="#{playersBean.dataHashMap.entrySet()}" var="t" border="1">
<h:column>
<f:facet name="header">Select</f:facet>
<h:selectOneRadio id="radiosId" onclick="deselectRadios(this.id);"
value="#{playersBean.select}">
<f:selectItem itemValue="null"/>
</h:selectOneRadio>
</h:column>
</h:dataTable>
<h:commandButton value="Show Hash Map Selection"
action="#{playersBean.showSelectedPlayer()}" />
</h:form>
With disselecting the other radio buttons when one radio button is selected being implemented by simple JavaScript-
function deselectRadios(id) {
var f = document.getElementById("hashMapFormId");
for (var i = 0; i < f.length; i++)
{
var e = f.elements[i];
var eid = e.id;
if (eid.indexOf("radiosId") !== -1) {
if (eid.indexOf(id) === -1) {
e.checked = false;
} else {
e.checked = true;
}
}
}
}
Fire the GET request:
Select a radio button:
Now press the submit button, response:
You see that the radio button gets dis selected on postback. How to solve this shortcoming?
I know it very well that this is due to this component attribute itemValue being null:
<f:selectItem itemValue="null"/>
This trick is a leftover from JSF 1.x / 2.0/2.1 when it wasn't possible to use a <h:selectOneRadio> for single row selection in a <h:dataTable>. This trick originated in my 10 year old blog article Using Datatables - Select row by radio button.
The root problem is, HTML radio buttons are grouped based on their name attribute, so the webbrowser knows which others to unselect when one is selected. But JSF generates by design a different one for each <h:dataTable> item, with the row index inlined and therefore they can't be grouped and hence the JavaScript based workaround.
Since JSF 2.2, with the new passthrough elements and attributes feature, it's however possible to force the name attribute to the value of your choice and capture the selected item via a helper <h:inputHidden>. This is fleshed out in another blog article of me, from previous year: Custom layout with h:selectOneRadio in JSF 2.2. The article uses <ui:repeat> as an example, this can be rewritten to <h:dataTable> as below.
<h:form>
<h:dataTable value="#{bean.items}" var="item">
<h:column>
<input type="radio" jsf:id="item" a:name="#{hiddenItem.clientId}"
value="#{item.id}" a:checked="#{item.id eq bean.selectedItemId ? 'checked' : null}" />
</h:column>
<h:column>#{item.id}</h:column>
<h:column>#{item.name}</h:column>
</h:dataTable>
<h:inputHidden id="selectedItem" binding="#{hiddenItem}" value="#{bean.selectedItemId}"
rendered="#{facesContext.currentPhaseId.ordinal ne 6}" />
<h:commandButton id="submit" value="Submit" action="#{bean.submit}" />
</h:form>
#Named
#ViewScoped
public class Bean implements Serializable {
private List<Item> items;
private Long selectedItemId;
// ...
public void submit() {
System.out.println("Selected item ID: " + selectedItemId);
}
// ...
}
And yes, the selected radio button remains selected on postback this way. You can also pass whole entities, this only requires a converter on the <h:inputHidden>.
I am trying to log the number of the button clicks.
1. Should log the number of clicks though the form is invalid. The field value1 in the form is integer. So, It shall also consider conversion errors.
2. Action to be done at backing bean
I have tried with listener on ajax.
<h:form id="form">
<h:inputText id="in" name="in" value="#{listenBean.value1}" autocomplete="off">
</h:inputText>
<h:commandButton value="Click Me" action="#{listenBean.save}">
<f:ajax execute="#form" render="#form message eventcount" />
</h:commandButton>
<h:message for="in"/>
Button Clicks: <h:outputText id="eventcount" value="#{listenBean.eventCount}"/>
</h:form>
Bean
public void eventCount(AjaxBehaviorEvent event) {
//increment the counter
}
public void save() {
//save
}
Issues:
The listener method is not called when the conversion errors on input field binded to integer at bean. I enter the value as "some text". During thsi time listener is not called.
Version: Mojaraa 2.2.8
Is this the correct way of doing. Am I doing any mistake.
Can some one help me.
The <h:outputText value> doesn't represent a method expression which should reference a bean (listener) method. It represents a value expression which should reference a bean property which will then be outputted as (escaped) text to the response.
Your best bet is to hook on preRenderView event of the component and check if the current request represents a postback request.
<h:form id="form">
<h:commandButton ...>
<f:ajax execute="#form" render="#form" />
</h:commandButton>
Button Clicks:
<h:outputText id="eventcount" value="#{listenBean.eventCount}">
<f:event type="preRenderView" listener="#{listenBean.incrementEventCount}" />
</h:outputText>
</h:form>
private int eventCount;
public void incrementEventCount(ComponentSystemEvent event) {
if (FacesContext.getCurrentInstance().isPostback()) {
eventCount++;
}
}
public int getEventCount() {
return eventCount;
}
Note that render="#form" covers the entire form already, so there's no need of specifying individual components inside the very same form. In case you've another ajax action inside the same form for which you'd like to not count the event, then make sure that render="..." is specific enough that it doesn't cover the eventcount component.
I have a Primefaces datatable and when the user clicks on a row, I display the data to edit in a form.
If the user changes the data in the form and clicks on any other row i.e if there is dirty data, I need to popup a confirmDialog to show if the user wants to save the data / discard it.
The confirmDialog does not display when I try to execute it from backing bean.
Any help is appreciated!
I have implemented it as follows:
.xhtml:
<p:dataTable id="tsTableId" value="#{transactionSetBean.studentList}" var="tsRow"
selectionMode="single" selection="#{transactionSetBean.selectedEditRec}" rowKey="#{tsRow.id}" scrollRows="10">
<p:ajax event="rowSelect" listener="#{transactionSetBean.onRowSelect}" update=":transactionSetsForm:tsEntryFrmId">
</p:ajax>
..
</p:dataTable>
ConfirmDialog:
<p:confirmDialog widgetVar="dataChangeDlg" message="Save changes Or Cancel">
<p:commandButton value="Save Changes" oncomplete="PF('dataChangeDlg').hide();"
update=":transactionSetsForm:messages :transactionSetsForm:tsEntryFrmId"
action="#{transactionSetBean.updateRecord}" />
<p:commandButton value="Cancel" onclick="PF('dataChangeDlg').hide();"
</p:confirmDialog>
Backing Bean:
public void onRowSelect(SelectEvent event)
{
String actionName = ON_ROW_SELECT;
try
{
Student selectedObj = (Student)event.getObject();
if (selectedObj != null)
{
selectedEditRec = selectedObj;
}
// if data is changed then show the dataChange dialog
if (isDataChanged())
{
setShowDataChangedDialog(true);
RequestContext context = RequestContext.getCurrentInstance();
// execute javascript and show dialog
context.execute("PF('dataChangeDlg').show();");
}
}
catch (Exception e)
{
handleException(e);
}
}
RequestContext.getCurrentInstance().execute("PF('dataChangeDlg').show();");
<p:ajax event="rowSelect" listener="#{transactionSetBean.onRowSelect}" update=":transactionSetsForm:tsEntryFrmId">
works for me.
There must be another error. maybe isDataChanged is false, wrong component ids in update or something.
With PrimeFaces >= 6.2
PrimeFaces.current().executeScript("PF('dataChangeDlg').show()");
I want to disable the button in case there is no value in the input text something like this:
<p:autoComplete id="ac" value="#{bean.selectedNet}"
completeMethod="#{bean.complete}"
minQueryLength="0" size="3">
<p:ajax event="itemSelect" update="genButton" listener="#{bean.handleNetChange}"/>
<p:ajax process="#this" update="genButton" />
</p:autoComplete>
<p:selectManyCheckbox id="en" layout="pageDirection" value="#{bean.selectedEntity}">
<f:selectItems value="#{bean.entityList}"/>
<p:ajax update="genButton" listener="#{bean.handleNetChange}"/>
</p:selectManyCheckbox>
<p:commandButton id="genButton" value="Generate Files"
widgetVar="startButton1"
disabled="#{bean.disableButton}"
actionListener="#{bean.generate}"
onclick="PrimeFaces.monitorDownload(showStatus, hideStatus)"
ajax="false">
<p:fileDownload value="#{bean.streamedContent}"/>
</p:commandButton>
Methods:
public void handleNetChange() {
if (!StringUtils.isBlank(selectedNet) && !selectedEntity.isEmpty()) {
disableButton = false;
} else {
disableButton = true;
}
}
public List<String> complete(String query) {
List<String> results = new ArrayList<String>();
if (StringUtils.isBlank(query)) {
selectedNet = query;
disableButton = true;
} else {
....
}
return results;
}
While the itemSelect event is working perfectly the second one is not. I can see the call to the complete method in the bean but the button is not updated
Any advise?
Seems like you can't force update just with <p:ajax process="#this" update="genButton" />.
I would try to update the button directly from the bean.
Since you are using primefaces you can use RequestContext; try to add this line to your complete method :
RequestContext.getCurrentInstance().addPartialUpdateTarget("genButton");
If you don't use prependId="false" on your wrapping form, you might need to specify the full path to the button e.g.:
RequestContext.getCurrentInstance().addPartialUpdateTarget("fooForm:genButton");
If you want to use disabled, do not use rendered property on command button.
<p:commandButton id="buttonId"
actionListener="#{controller.function}"
value="#{controller.label}"
disabled="#{controller.disableButton}" rendered="#{controller.renderButton}" />
After removing rendered, button gets disabled without any issues.