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()");
Related
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));
}
I have a primefaces datatable with a <p:commandLink> in each row. The user clicks it to see a different page with details about the record he selected. It was working fine until I add a filteredValue in my datatable. I need this attribute (filteredValue) in order to correctly filter and sort my datatable, as shown in this question.
But after adding this attribute, my commandLink stops working. How can I make it work with the attribute?
Here's my datatable:
<p:dataTable var="prot" value="#{myBean.listaProtocolos}" rows="15" filteredValue="#{myBean.listaProtocolosFiltrados}" sortBy="#{prot.dataEntradaArea}" sortFunction="#{myBean.sortXMLDatas}" sortOrder="descending" paginator="true" style="font-size: 0.9em;" paginatorPosition="bottom">
<p:column filterBy="${prot.nrProtocolo}" filterMatchMode="contains" width="8%" style="text-align:center">
<f:facet name="header">ID</f:facet>
<p:commandLink action="#{myBean.verDetalhesProtocolo}" process="#this messages" update="#this messages">
<h:outputText value="#{prot.nrProtocolo}" style="text-decoration: underline;"/>
<f:setPropertyActionListener target="#{myBean.nrProtocolo}" value="#{prot.nrProtocolo}" />
</p:commandLink>
</p:column>
(etc)
and the relevant pieces of myBean:
public void verDetalhesProtocolo() {
for(ProtocoloMY pro : this.listaProtocolos){
if(pro.getNrProtocolo().trim().equalsIgnoreCase(this.nrProtocolo.trim())) {
this.protocolo = new ProtocoloMY(pro);
break;
}
}
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.getExternalContext().redirect("detalhes_protocolo_processo.xhtml");
//(This method isn't even called when I add the attribute filteredValue to my datatable)
public String getNrProtocolo() {
return nrProtocolo;
}
public void setNrProtocolo(String nrProtocolo) {
this.nrProtocolo = nrProtocolo;
}
public List<ProtocoloMY> getListaProtocolos() {
return listaProtocolos;
}
public List<ProtocoloMY> getListaProtocolosFiltrados() {
return listaProtocolosFiltrados;
}
public void setListaProtocolosFiltrados(List<ProtocoloMY> listaProtocolosFiltrados) {
this.listaProtocolosFiltrados = listaProtocolosFiltrados;
}
public void setListaProtocolos(List<ProtocoloMY> listaProtocolos) {
this.listaProtocolos = listaProtocolos;
}
And I almost forgot to say: There's some network traffic happening when I click the link, but nothing is shown in my backend console and the method in my bean isn't called.
I'm running primefaces v6.0.
For PrimeFaces to be able to track which row by its unique id you need to add the attribute rowKey="#{row.id}" to your p:datatable using whatever value in your row POJO that makes it unique.
I want to update a button in the header facet of a primefaces datatable and it does not work. I copied the button outside the datatable everything works fine.
The update should happen when the filter event of the datatable gets fired. I explicitly update the datatable, the outside- and the inside-button.
The intention is to display a button with an icon when no filter is set and another icon when a filter is used. In this example I simplyfied the use case: when no filter is used there is a open-lock icon, if I type something in a filter a closed-lock icon should be displayed. To release the lock one has to click the button (I did not implement the deletion of the filter in the datatable).
From what I understand I use the correct ID of the button inside the header. So I do not know why this does not work?
I am using mojarra 2.2 and primefaces 6.
<h:form id="id_form">
<p:dataTable
id="id_table"
value="#{stateController.names}"
var="currentName">
<p:ajax
event="filter"
listener="#{stateController.markLocked()}"
update="id_table id_form:id_table:id_button_inside id_form:id_button_outside"/>
<p:column
filterBy="#{currentName}"
filterMatchMode="contains">
<f:facet name="header">
<p:commandButton
id="id_button_inside"
action="#{stateController.markUnlocked()}"
icon="#{stateController.locked ? 'ui-icon-locked' : 'ui-icon-unlocked'}"
update="id_form"/>
</f:facet>
<h:outputText value="#{currentName}" />
</p:column>
</p:dataTable>
<p:commandButton
id="id_button_outside"
action="#{stateController.markUnlocked()}"
icon="#{stateController.locked ? 'ui-icon-locked' : 'ui-icon-unlocked'}"
update="id_form"
/>
</h:form>
#Named(value = "stateController")
#SessionScoped
public class StateController implements Serializable
{
private boolean locked;
private List<String> names;
#PostConstruct
private void init()
{
locked = false;
names = new ArrayList<>();
names.add("peter");
}
public void markLocked()
{
locked = true;
}
public void markUnlocked()
{
locked = false;
}
// getter + setter omitted
}
I also tried to put a button in a separate column. With this button (which is displayed in every row of the datatable) everything works fine as well.
It's a bit late, but maybe someone will find it useful some day.
To solve Filou's problem, you need to define remoteCommand outside dataTable and make it update dataTable's header facet.
<p:remoteCommand name="rmtCommand" update="id_form:id_table:id_button_inside"/>
<p:dataTable
id="id_table"
value="#{stateController.names}"
var="currentName">
<p:ajax
event="filter"
listener="#{stateController.markLocked()}"
oncomplete="rmtCommand()"/>
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)" />
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.