BootsFaces-OSP
BootsFaces-OSP copied to clipboard
How to use AJAX with b:datatable (originally: The FacesMessages are not shown when are called from a row of a datatable)
I have a Datatable with a list of items and with each item I have a column with a button that if you click it, this item will be deleted if possible, if not it will throw a FacesMessages, but the FacesMessage is not shown, although in the JSF page there is the growl component.
could you provide a short code example showing relevant portions of your xhtml and backing bean?
Portion of the xhtml:
<b:row styleClass="table-responsive">
<b:dataTable id="cars" var="car" value="#{carsView.cars}" searching="false"
excel="true" csv="true" pdf="true" columnVisibility="true" copy="true" print="true"
multi-column-search='true' multi-column-search-position='top' searchable='false'
page-length="5" page-length-menu="5,10,20">
<b:dataTableColumn label="Brand">
<h:outputText value="#{car.brand}"/>
</b:dataTableColumn>
<b:dataTableColumn value="#{car.number}" label="Number Plate">
</b:dataTableColumn>
<b:dataTableColumn label="Comments">
<h:outputText value="#{car.comments}" />
</b:dataTableColumn>
<b:dataTableColumn label="Borrar">
<center><b:commandButton update="@form" look="danger"
onclick="ajax:carsView.deleteCar(car)" class="fa fa-remove fa-lg" /></center>
</b:dataTableColumn>
</b:dataTable>
</b:row>
<b:row>
<b:growl id="growl" globalOnly="true" showDetail="true"
severity="info,warn, error, fatal"/>
</b:row>
</h:form>
Portion of the backing bean:
public void deleteCar(Car car) {
carRepository.delete(car);
cars.remove(car);
FacesMessages.info("Info", "The car has been deleted");
}
is the row deleted? have you tried adding a faces message using this method:
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO,
"The car has been deleted", null));
i note that your growl is set for global only although i am not sure if that makes any difference
@chongma "global only" should be OK, because the FacesMessage
doesn't bear an id.
Yes, the row is deleted. I have tried your suggestion, but it continues not showing the message. Maybe the fact that in the same view there are models avoids to see the message.
could you post the full xhtml form? it is possible the b:growl
is not positioned correctly in the form. maybe create a simple test form where a simple command button generates a FacesMessage. e.g.
XHTML
<h:form>
<b:growl/>
<b:commandButton value="test" action="#{myBean.test}">
<f:ajax render="@form"/>
</b:commandButton>
</h:form>
backing bean
public String test() {
FacesContext.getCurrentInstance().addMessage(null,
new FacesMessage(FacesMessage.SEVERITY_INFO,
"Testing growl", null));
}
The full xhtml form is the following:
<h:form>
<b:row styleClass="placeholders">
<p:fileUpload fileUploadListener="#{carsView.handleFileUpload}" mode="advanced"
update="messages" auto="true" allowTypes="/(\.|\/)(xlsm|xls|xlsx)$/" label="Import Excel of Cars">
</p:fileUpload>
<p:growl id="messages" showDetail="true" />
</b:row>
<b:modal id="amodal1" title="Contacts of #{carsView.selectedCar.id}" styleClass="modalPseudoClass1" closable="false" close-on-escape="false" backdrop="false">
<b:dataTable id="contacts" var="contact" value="#{carsView.selectedCar.contacts}" class="editableContactoTable" responsive="true" widgetVar="tableWidgetVar" scroll-horizontally="true">
<b:dataTableColumn label="Main Contact">
<h:outputText value="#{contact.fullName}"/>
</b:dataTableColumn>
<b:dataTableColumn label="Telephone Number">
<h:outputText value="#{contact.telephone}" />
</b:dataTableColumn>
</b:dataTable>
<f:facet name="footer">
<b:button value="Cerrar" dismiss="modal"/>
</f:facet>
</b:modal>
<b:row styleClass="table-responsive">
<b:dataTable id="cars" var="car" value="#{carsView.cars}" searching="false"
excel="true" csv="true" pdf="true" columnVisibility="true" copy="true" print="true"
multi-column-search='true' multi-column-search-position='top' searchable='false'
page-length="5" page-length-menu="5,10,20">
<b:dataTableColumn label="Brand">
<h:outputText value="#{car.brand}"/>
</b:dataTableColumn>
<b:dataTableColumn value="#{car.number}" label="Number Plate">
</b:dataTableColumn>
<b:dataTableColumn label="Comments">
<h:outputText value="#{car.comments}" />
</b:dataTableColumn>
<b:dataTableColumn label="Contacts" searchable="false">
<center><b:commandButton update="@form" look="info" oncomplete="$('.modalPseudoClass1').modal()" onclick="ajax:carsView.onclickCar(car)" class="fa fa-table fa-lg"/></center>
</b:dataTableColumn>
<b:dataTableColumn label="Delete">
<center>
<b:growl/>
<b:commandButton look="danger" action="#{carsView.test}" class="fa fa-remove fa-lg">
<f:ajax render="@form"/>
</b:commandButton>
</center>
</b:dataTableColumn>
</b:dataTable>
<b:commandButton update="@form" col-sm="2" look="info" onclick="ajax:carsView.addCar()" class="fa fa-plus fa-lg" />
</b:row>
</h:form>
your b:growl
component is in the loop of the b:dataTable
so i imagine the html will create multiple growl components. try moving it to just below the h:form
declaration
also i note you have a p:growl
and a b:growl
. you should only need one?
I have edited the xhtml form, and now I can see the messages. But, I continue with two problems: 1.- When an Ajax event occurs the searching and pagination of the database dissapear. 2.- The searching of the columns does not work. I copy my xhtml form:
<p:messages id="messages"/>
<h:form>
<b:row styleClass="placeholders">
<p:fileUpload fileUploadListener="#{carsView.handleFileUpload}" mode="advanced"
update="messages @(.editableCarTable)" auto="true" allowTypes="/(\.|\/)(xlsm|xls|xlsx)$/" label="Import Excel of Cars">
</p:fileUpload>
</b:row>
<b:modal id="amodal1" title="Contacts of #{carsView.selectedCar.id}" styleClass="modalPseudoClass1" closable="false" close-on-escape="false" backdrop="false">
<b:dataTable id="contacts" var="contact" value="#{carsView.selectedCar.contacts}" class="editableContactoTable" responsive="true" widgetVar="tableWidgetVar" scroll-horizontally="true">
<b:dataTableColumn label="Main Contact">
<h:outputText value="#{contact.fullName}"/>
</b:dataTableColumn>
<b:dataTableColumn label="Telephone Number">
<h:outputText value="#{contact.telephone}" />
</b:dataTableColumn>
</b:dataTable>
<f:facet name="footer">
<b:button value="Cerrar" dismiss="modal"/>
</f:facet>
</b:modal>
<b:row styleClass="table-responsive">
<b:dataTable id="cars" var="car" value="#{carsView.cars}" searching="true"
excel="true" csv="true" pdf="true" columnVisibility="true" copy="true" print="true"
multi-column-search='true' multi-column-search-position='top' searchable='false'
searchable='false' page-length="5" page-length-menu="5,10,20" class="editableCarTable">
<b:dataTableColumn label="Brand">
<h:outputText value="#{car.brand}"/>
</b:dataTableColumn>
<b:dataTableColumn value="#{car.number}" label="Number Plate">
</b:dataTableColumn>
<b:dataTableColumn label="Comments">
<h:outputText value="#{car.comments}" />
</b:dataTableColumn>
<b:dataTableColumn label="Contacts" searchable="false">
<center><b:commandButton update="@form" look="info" oncomplete="$('.modalPseudoClass1').modal()" onclick="ajax:carsView.onclickCar(car)" class="fa fa-table fa-lg"/></center>
</b:dataTableColumn>
<b:dataTableColumn label="Delete" searchable="false">
<center>
<b:commandButton look="danger" action="#{carsView.test}" class="fa fa-remove fa-lg">
<f:ajax render="@form"/>
</b:commandButton>
<b:commandButton update="messages @(.editableCarTable)" look="danger" onclick="ajax:carsView.deleteCar(car)" class="fa fa-remove fa-lg" />
</center>
</b:dataTableColumn>
</b:dataTable>
<b:commandButton update="@form" col-sm="2" look="info" onclick="ajax:carsView.addCar()" class="fa fa-plus fa-lg" />
</b:row>
</h:form>
-
p:messages
is outside the form. it should be inside the form to report messages which are relevant to the form - normally i would place a
b:modal
outside the form - you are updating multiple elements eg
update="messages @(.editableCarTable)"
whereas i would advise updating the whole formupdate="@form"
at least until you know what you are doing (i normally only update the form as it is a headache to update small elements). this is a personal choice... - some of your
b:commandButton
elements might not use ajax?ajax="true"
or<f:ajax render="@form" />
I implement the recommendations you gave me, but it continues dissapearing the searching and pagination of the datatable, and the searching of the columns does not work neither.
You will need to provide a working example project which reproduces the problem otherwise it will be difficult for us to pinpoint the problem. You could use a maven archetype as a starting point
@mmncd If your AJAX request replaces the entire table, you have to destroy and re-initialize it. Have a look at the documentation of the AJAX behaviour of the datatable.
With the destroy table method, the database remains with the researching, but not with the pagination. Moreover, it is not updated with the deleted row. As opposed to without this method that at least the deleted row is not displayed.
<h:form id="form">
.
.
.
<b:commandButton ajax="true" update="messages @(.editableCarTable)"
look="danger"
onclick="formCarsWidget.DataTable().destroy();ajax:carsView.deleteCar(car)"
class="fa fa-remove fa-lg" />
@mmncd Sorry for the long pause. Did you find a solution in the meantime? Or do you still need assistance?
As far as I understand,
- you've managed to solve the bug you originally reported,
- but the datatable still doesn't work as you expect it to do. In particular,
- it's not updated after deleting the row (i.e. you delete a row, but it's still visible after the AJAX request),
- and the paginator is lost after the AJAX request.
On the plus side, the "search" input field is there, and it keeps working even after the AJAX request.
Did I summary the current state of the art correctly?
I'm afraid development of BootsFaces has slowed down considerably. We'll never manage to address this issue. Let's close it.