Unable to disable <p:commandButton> via ajax - jsf

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.

Related

JSF inputSwitch with confirmDialog

I have a inputSwitch that need to show a dialog to confirm or not the operation. The dialog should show a variable message if i put it on or off.
I do the next thing but the problem is when i push no and i toggle the switch to let in then original state it call the ajax event again and open the dialog again. How can i lauch the event only when i click and not when i call the .toggle function?
<p:outputLabel for="activa"
value="#{bundleBean.getValue('activa')}" />
<p:inputSwitch id="activa"
value="#{gestionBean.domainEntity.activa}" onLabel="Si"
offLabel="No"
widgetVar="switch#{gestionBean.domainEntity.id}">
<p:ajax event="change" update="test" oncomplete="PF('dialog#{gestionBean.domainEntity.id}').show()"></p:ajax>
</p:inputSwitch>
<div>
<p:confirmDialog id="test"
widgetVar="dialog#{gestionBean.domainEntity.id}"
styleClass="content-confirmation-dialog"
message="#{gestionBean.mensajeDialogoActiva(gestionBean.domainEntity.activa)}"
header="#{bundleBean.getValue('confirmacion')}" closable="false">
<p:commandButton value="Si"
styleClass="boton rounded-button ui-button-danger float-right ui-confirmdialog-yes" immediate="true"
onclick="PF('dialog#{gestionBean.domainEntity.id}').hide()" />
<!-- action="#{gestionBean.cambiarEstado(gestionBean.domainEntity)}" -->
<p:commandButton value="No" styleClass="boton rounded-button ui-button ui-confirmdialog-no"
immediate="true"
update="activa"
onclick="PF('switch#{gestionBean.domainEntity.id}').toggle(); PF('dialog#{gestionBean.domainEntity.id}').hide()" />
</p:confirmDialog>
You can update the form, instead of the switch, when you click the No button and the dialog will not be shown.
<p:commandButton update="#from">
An alternative approach to solve this problem is to do away with the p:confirmDialog and instead have the change event on the p:inputSwitch / p:toggleSwitch trigger a click event on a hidden commandButton. For example:
<p:inputSwitch id="toggle" value="#{toggleSwitchController.toggleOn}" >
<p:ajax oncomplete="PF('hidnBtn').getJQ().click();"/>
</p:inputSwitch>
<p:commandButton id="hiddenBtn" widgetVar="hidnBtn"
action="#{toggleSwitchController.toggleChanged}"
style="visibility: hidden;">
<p:ajax event="dialogReturn" update=":frm1:growl toggle"
listener="#{toggleSwitchController.handleReturn}" />
</p:commandButton>
The action that the hidden p:commandButton calls can test the value of the toggle and if set to true/yes use PrimeFace's dialog framework to show a confirmation dialog. The dialog can return a boolean, which can be tested in the handleReturn function.
public void toggleChanged() {
if (toggleOn) {
Map<String, Object> options = new HashMap<>();
options.put("resizable", false);
options.put("draggable", false);
options.put("closable", false);
options.put("modal", true);
PrimeFaces.current().dialog().openDynamic("/pages/pleaseConfirm", options, null);
}
}
public void handleReturn(SelectEvent<Boolean> event) {
boolean confirmed = event.getObject();
if (confirmed) {
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "confirmed", null));
} else {
facesContext.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "not confirmed", null));
toggleOn = false;
}
}
You could make the "pleaseConfirm" dialog more reusable by providing parameters for the text strings through the openDynamic() call.
The problem can be solved by adding a listener to the ajax change event, making the listener return the current value of the toggle and testing the returned value in the onComplete clause before showing the dialog.
<p:inputSwitch id="activa"
value="#{toggleSwitchController.toggleOn}"
onLabel="Si" offLabel="No"
widgetVar="toggleWidget" >
<p:ajax event="change"
listener="#{toggleSwitchController.testToggle}"
update="test"
oncomplete="if ( args.toggleValue == 1 ) { PF('dlgWidget').show();}" />
</p:inputSwitch>
The listener can be very simple:
public void testToggle() {
PrimeFaces.current().ajax().addCallbackParam("toggleValue", (toggleOn ? 1 : 0));
}

How to pass the selected values from selectcheckBoxMenu to my bean?

I'm using JSF 2.2.8 and primefaces 6.0, and i have a selectCheckBoxMenu i want to retrieve the selected values in my bean.
The selectCheckboxMenu is filled from the database but when i select the attributes and I save nothing happens it does not call the save function
Here is my selectCheckBoxMenu
<p:outputLabel for="ressource" value="Ressource"/>
<h:panelGroup >
<p:selectCheckboxMenu id="ressource" label="Ressource" value="#{affectationBean.selectedRessource}" multiple="true">
<f:selectItems value="#{affectationBean.ressources}" var="r" itemLabel="#{r.nom}" itemValue="r.idt_ressource" />
</p:selectCheckboxMenu>
</h:panelGroup>
<p:commandButton icon="ui-icon-save" actionListener="#{affectationBean.save}" value="Save" update="#affectation" ajax="false" style="display:inline-block;margin-top:5px"/>
Here is the the declaration of the selectedRessource and the actionListener save
private Long [] selectedRessource;
// Getters setters and Construct
public void save(){
for(int i=0 ;i<selectedRessource.length;i++){
system.out.println("id ===> " + selectedRessource[i]);
}
My suggestion would be:
First make sure everything is inside the h:form tag.
don't need to multiple = true as this tag does not take this attribute
i tested with below modification and got the selected multiple value in my bean. The only difference is i am using same value for itemLabel and itemValue but in your case it is object. i am using primefaces 6 also and dont even need to change actionListner to action. It is working as it is.sample xhtml
sample ResourceBean.java
<p:outputLabel for="ressource" value="Ressource"/>
<h:panelGroup >
<p:selectCheckboxMenu id="ressource" label="Ressource" value="#{resourceBean.selectedRessource}">
<f:selectItems value="#{resourceBean.ressources}" var="r" itemLabel="#{r}" itemValue="#{r}" />
</p:selectCheckboxMenu>
</h:panelGroup>
<p:commandButton icon="ui-icon-save" actionListener="#{resourceBean.save}" value="Save" ajax="false" style="display:inline-block;margin-top:5px"/>
The problem is in your p:commandButton, you have 3 options
change your method:
public void save(ActionEvent actionEvent){...}
change your action listener value:
actionListener="#{affectationBean.save()}"
or change your button to use action
action="#{affectationBean.save}"
DISCLAIMER: This is a workaround. It is not intended to be a permanent solution but will allow you to use selectCheckboxMenu and keep working.
There is an issue with this component that prevents it from passing values to the backing bean upon submit.
For some reason the array that should contain the selected values gets cleared out upon submit. Therefore I made an extra array that I did not declare in the tag, and updated in on every change event. Then on submit the values were still there. See below:
BackingBean.java
private String[] sCodes;
private String[] sCodes2; //extra array, not in form.xhtml
public void updateCodes()
{
sCodes2 = sCodes; //keeps the values in the other array
}
public void doSend() throws IOException
{
log.trace("selected codes: {} selected codes2 length: {}", sCodes.length, sCodes2.length);
}
form.xhtml
<p:selectCheckboxMenu id="codeCtl" value="#{bean.SCodes}" label="Codes" filter="true" filterMatchMode="startsWith" panelStyle="width:250px">
<f:selectItems value="#{bean.menuCodes}" />
<p:ajax event="change" listener="#{bean.updateCodes()}" />
</p:selectCheckboxMenu>
<p:commandButton value="submit" actionListener="#{bean.doSend}" id="ctlSubmit" update="appform"/>

submit button does not submit but only triggers InputText's onChange event

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)" />

Displaying Primefaces confirmDialog from Backing Bean

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()");

How to get the selected item from an p:orderList?

I want to get the selected item from an orderList. It seems to me that this functionality is missing. Is there a functionality in PF? Or is there a possible workaround?
I really appreciate your answer!
My technology stack:
Hibernate: 4.0.1.Final
Spring: 3.1.1.RELEASE
Primefaces: 3.5
jsf-version: 2.2.0-m08
PrimefacesMobile-version: 0.9.3
Apache Tomcat/7.0.12
I've resolved this by using a button for delete. The code snippet is below:
<p:orderList id="layersList" value="#{mappingLayerController.layers}"
converter="layerConverter" var="layer" itemValue="#{layer}"
controlsLocation="left">
<p:column>
<h:outputText value="#{layer.layerName}"/>
</p:column>
<p:column style="width: 4%">
<p:commandButton icon="ui-icon-close" actionListener="#{controller.deleteLayer()}">
<f:param name="layerName" value="#{layer.layerName}" />
</p:commandButton>
</p:column>
</p:orderList>
And in the backing bean you can get the supplied parameter via the f:param tag as:
String layerName = FacesContext.getCurrentInstance().getExternalContext().getRequestParameterMap().get("layerName");
I hope this helps.
I ran into the same issue trying to create an edit action for each item in my orderList. I tried passing my var to the action, creating an action listener in combination with an attribute, and a select listener all without success.
I ended up using a dataTable ... draggableRows="true" (see data table reorder in showcase). In the data table I could simply pass my var as a parameter to an action... So I thought. I ran into the issue that after reordering, clicking the edit button gave me the wrong item. I created a workaround being that on reorder I update the model and redraw the table. It works, but doesn't feel right.
<p:dataTable id="myTable"
value="#{myBean.myItems}"
var="item"
sortBy="#{item.orderNumber}" sortOrder="ascending"
draggableRows="true">
...
<p:column headerText="Actions">
<p:commandButton title="Edit"
action="#{myBean.edit(item)}"
process="#this">
</p:column>
<p:ajax event="rowReorder"
listener="#{myBean.onSlotContentReorder}"
update="myTable"/>
</p:dataTable>
It is possible in PrimeFaces 5 and higher. There is no out of box feature, but it can be easily achieved with additional list of selected items. See example
Java code
private List<Record> allItems; // with getter and setter
private List<Record> selectedItems; // with getter and setter
public void onSelect(SelectEvent event) {
if (null == event || null == event.getObject()) {
return;
}
if (!event.isCtrlKey()) {
setSelectedItems(new ArrayList<Record>());
}
Record item = (Record)event.getObject();
if (!getSelectedItems().contains(item)) {
getSelectedItems().add(item);
}
}
public void onUnselect(UnselectEvent event) {
if (null == event || null == event.getObject()) {
return;
}
Record item = (Record)event.getObject();
if (getSelectedItems().contains(item)) {
getSelectedItems().remove(item);
}
}
public void deleteSelected() {
if (getAllItems().isEmpty()) {
addErrorMessage("listEmpty");
return;
}
if (getSelectedItems().isEmpty()) {
addErrorMessage("noItemSelected");
return;
}
for (Record item : getSelectedItems()) {
if (getAllItems().contains(item)) {
getAllItems().remove(item);
}
}
}
XHTML
<h:panelGroup id="listGroup">
<p:orderList id="list" value="#{bean.allItems}"
var="item" itemLabel="#{item.code}" itemValue="#{item}"
converter="#{itemConverter}" controlsLocation="none">
<f:facet name="caption">#{msg.listName}</f:facet>
<p:ajax event="select" listener="#{bean.onSelect}" />
<p:ajax event="unselect" listener="#{bean.onUnselect}" />
</p:orderList>
<p:contextMenu id="listMenu" for="list">
<p:menuitem value="#{msg.delete}"
actionListener="#{bean.deleteSelected}"
update="listGroup, messages"
rendered="#{not empty bean.allItems}" />
</p:contextMenu>
</h:panelGroup>

Resources