TheCoder4eu / BootsFaces-OSP

BootsFaces - Open Source Project
Apache License 2.0
246 stars 102 forks source link

How to use AJAX with b:datatable (originally: The FacesMessages are not shown when are called from a row of a datatable) #961

Closed mmncd closed 2 months ago

mmncd commented 6 years ago

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.

chongma commented 6 years ago

could you provide a short code example showing relevant portions of your xhtml and backing bean?

mmncd commented 6 years ago

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");
}
chongma commented 6 years ago

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

stephanrauh commented 6 years ago

@chongma "global only" should be OK, because the FacesMessage doesn't bear an id.

mmncd commented 6 years ago

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.

chongma commented 6 years ago

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));
}
mmncd commented 6 years ago

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>
chongma commented 6 years ago

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

chongma commented 6 years ago

also i note you have a p:growl and a b:growl. you should only need one?

mmncd commented 6 years ago

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>
chongma commented 6 years ago
  1. p:messages is outside the form. it should be inside the form to report messages which are relevant to the form
  2. normally i would place a b:modal outside the form
  3. you are updating multiple elements eg update="messages @(.editableCarTable)" whereas i would advise updating the whole form update="@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...
  4. some of your b:commandButton elements might not use ajax? ajax="true" or <f:ajax render="@form" />
mmncd commented 6 years ago

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.

chongma commented 6 years ago

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

stephanrauh commented 6 years ago

@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.

mmncd commented 6 years ago

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" />
stephanrauh commented 6 years ago

@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,

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?

stephanrauh commented 2 months ago

I'm afraid development of BootsFaces has slowed down considerably. We'll never manage to address this issue. Let's close it.