Creating an async event inside a dataTable column and rendering a button according to response

Creating an async event inside a dataTable column and rendering a button according to response

karankiakarankia Posts: 10Questions: 1Answers: 0

I am using dataTables to represent a list of institutions. One of the columns in the table has button to check API status, so when a user clicks it will say if the API is active or inactive. I have this working but now I will like to make it an async event so when the page or the dataTable is loaded we get the status of the API after few seconds automatically, how can I achieve this as I am unable to find anything useful regarding this. Below is my code.

 $.ajax({
    url: '/getInstitutionsList',
    type: 'GET',
    dataType: 'JSON',
    success: function(response) {
        var institutionsTable = $('#institutionsTable').DataTable({
            responsive: true,
            data: response.data,
            language: dataTableLang,
            columns: [
                { data: null, defaultContent: '' },
                { data: 'description' },
                { data: 'email' },
                { data: 'phone' },

                {
                    data: null,
                    render: function (data, type, row) {

                        if (locale === 'fr') {
                            return "<button class=\"btn button-status btn-primary btn-sm ml-4 mb-2\"  id= 'checkApiStatus" + data.id_institutions + "' data-instituteid='"+ data.id_institutions +"'> "+ frLocaleDataTable['CHECK API STATUS'] + " <i id='spinner" + data.id_institutions +"' class=\"fa fa-spinner fa-spin hidden\"></i></button>"
                        } else {
                            return "<button class=\"btn button-status btn-primary btn-sm ml-4 mb-2\"  id= 'checkApiStatus" + data.id_institutions + "' data-instituteid='"+ data.id_institutions +"'>Check API Status<i id='spinner" + data.id_institutions +"' class=\"fa fa-spinner fa-spin hidden\"></i></button>"
                        }

                    }

                },
                {
                    data: null,
                    render: function (data, type, row) {
                        return " <button class=\"button-expire btn-sm ml-4 mb-2\" style=\"border:none;\" data-instituteid='"+ data.id_institutions +"'><i class=\"fa fa-clock\"></i></button>"
                    }
                },
                { data: 'id_institutions' },
                {
                    data: null,
                    render: function (data, type, row) {
                        return " <button class=\"button-manage btn-sm ml-4 mb-2\" style=\"border:none;\" data-instituteid='"+ data.id_institutions +"'><i class=\"fa fa-pencil-alt\"></i></button>"
                    }
                },
                {
                    data: null,
                    render: function (data, type, row) {
                        return " <button class=\"button-delete btn-sm ml-4 mb-2\" style=\"border:none;\" data-instituteid='"+ data.id_institutions +"'><i class=\"fa fa-trash\"></i></button>"
                    }
                }
            ],
            columnDefs: [
                {
                    targets: [6],
                    visible: false,
                    searchable: false
                },
                {
                    targets: [0],
                    checkboxes: {
                        selectRow: true
                    }
                }

            ],
            select: {
                style: 'multi'
            },
            pageLength: 5,
            order: [[ 1, 'asc' ]],
            bDestroy: true,

        });

    }

});

Below is the event on button with button-status class click

 $('.button-status').click(function (e){
        e.preventDefault();
        var instituteId = $(this).data('instituteid');
        $('#spinner' + instituteId).removeClass('hidden');
        $.ajax({
            url: '/getInstitutionStatus/' + instituteId,
            type: 'GET',
            dataType: 'json',
            success: function(response) {
                $('#spinner' + instituteId).hide();
                document.getElementById('checkApiStatus' + instituteId).classList.remove('btn-primary');
                document.getElementById('checkApiStatus'  + instituteId).classList.add('btn-success');
                document.getElementById('checkApiStatus'  + instituteId).innerText = 'Active';


            }, error: function (e) {
                $('#spinner' + instituteId).hide();
                document.getElementById('checkApiStatus'  + instituteId).classList.remove('btn-primary');
                document.getElementById('checkApiStatus'  + instituteId).classList.add('btn-danger');
                document.getElementById('checkApiStatus'  + instituteId).innerText = 'Inactive';
                $("#overlay").fadeOut(2000);
                document.getElementById('errorDiv'  + instituteId).innerHTML = '<p class="p-3">' + e.message + '</p>';
            }
        });

    });

Here is the screenshot of the dataTable with the buttons for reference
https://i.stack.imgur.com/ZFkig.png

This question has an accepted answers - jump to answer

Answers

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736

    Its unclear to me if you are wanting to refresh the whole table periodically or just a particular row. I'll assume the whole table:

    One option is to use ajax to load the table data instead of the jQuery ajax call you are using. Then use setTimeout() to execute ajax.reload().

    Or you can use a jQuery ajax request to refresh the data. Use clear() followed by rows.add() in the success function. Place this request in a setTimeout() function.

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0

    @kthorngren So no I just want to refresh the API state column, so when the page loads if the API returns a response the button in that row should say active or otherwise inactive

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736
    edited December 2021

    My understanding is the above code works when clicking a button but you want to do this:

    like to make it an async event so when the page or the dataTable is loaded we get the status of the API after few seconds automatically,

    Please provide more details of how this will work. Currently you load some data when the Datatable initializes. How are you planning to get the status of the API after a few seconds? Does the status data have an id that can be used to know the row to update? Is the status for all rows or just some?

    The rowCallback and drawCallback callbacks are used to update the Datatables data after initialization. Maybe one of those callbacks will work.

    Kevin

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736

    Maybe you can add the status as part of the row data, it doesn't need to be displayed in a column. In columns.render use that status to set the button appropriately. When the status is updated via the API update each row with the status using row().data() or cell().data(). Then use draw() to draw the table which will run the columns.render function.

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0
    edited December 2021

    @kthorngren So currently, I use the 'id_institutions' from my response which is used to generate the datatable, In my dataTable columns render function, I add this value to html data attribute, so when the user clicks the button, a call is submitted to the API. But this needs to be automatic/async event so when the page is loaded we should get the status automatically. Here is code for the column that renders the button

                        {
                            data: null,
                            render: function (data, type, row) {
    
                            if (locale === 'fr') {
                                return "<button class=\"btn button-status btn-primary btn-sm ml-4 mb-2\"  id= 'checkApiStatus" + data.id_institutions + "' data-instituteid='"+ data.id_institutions +"'> "+ frLocaleDataTable['CHECK API STATUS'] + " <i id='spinner" + data.id_institutions +"' class=\"fa fa-spinner fa-spin hidden\"></i></button>"
                            } else {
                                return "<button class=\"btn button-status btn-primary btn-sm ml-4 mb-2\"  id= 'checkApiStatus" + data.id_institutions + "' data-instituteid='"+ data.id_institutions +"'>Check API Status<i id='spinner" + data.id_institutions +"' class=\"fa fa-spinner fa-spin hidden\"></i></button>"
                            }
    
                        }
    
                    }
    
  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736
    edited December 2021

    But this needs to be automatic/async event so when the page is loaded we should get the status automatically.

    Click the button and url: '/getInstitutionStatus/' + instituteId, is fetched and the status is updated in the success function, correct?

    Instead of the button you want to fetch all of the instituteId statuses then update the table. Is this correct?

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0

    @kthorngren Yes thats correct, sorry it took so long to explain, English is not my first language

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736

    You will use a jQuery ajax() request to fetch the updated status. You can do this in initComplete if you want to what until after Datatables initializes. Or you can use some other trigger to send the request.

    I'm still not sure if the status is part of the row data but I will assume it is. I would use the success function to use rows().every() to iterate all the rows. Then use row().data() or cell().data() to update the row status. After the loop use draw() to update the table display and the status.

    You can use rowId to set the row id to the instituteId. In the rows().every() loop you can use -api row().id() to get the current instituteId to apply the new status.

    Sorry I'm just providing some vague random ideas that will hopefully help. I still don't understand the details of how you want to fetch the data and what is returned. Hope these ideas give you a start.

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0

    @kthorngren So status is not part of the row data, only the 'instituteId' is a part. I am fetching the status by clicking the button-status with instituteId data-attribute. So when I click the button I make an ajax API call to /getInstitutionStatus/' + instituteId, If its a success that means the status is active otherwise its inactive

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736

    when I click the button I make an ajax API call to /getInstitutionStatus/' + instituteId, If its a success that means the status is active otherwise its inactive

    Does this work or is this what you are trying to fix?

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0
    edited December 2021

    @kthorngren, yes the button click works with the my code on top. But its not an asynchronous event, so the issue is to fetch the status automatically. So when the page loads the dataTable is created and then after few seconds/minutes the status column values refresh depending on the status being active or inactive, so the user doesn't have to click the button to know the status

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736
    edited December 2021

    So when the page loads the dataTable is created and then after few seconds/minutes the status column values refresh depending on the status being active or inactive

    Are you planning to use a jQuery ajax() request for this? If so what will be returned?

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0

    @kthorngren Yes, I think that is the only way I see it. So the response will return an active/inactive status.

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736
    edited December 2021

    Is the response for one instituteId? Or will you fetch more than one at a time?

    What will trigger the ajax request?

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0
    edited December 2021

    @kthorngren No the response will be for multiple 'instituteId' and the ajax request should be automatic request after the datatable has loaded, so once the table has loaded it should query the status automatically according to the number of rows and update the status column of each row once it gets the response.

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736

    the response will be for multiple 'instituteId'

    Use rowId to set the tr id to the 'instituteId'. This way you can use the row() row-selector as a string-#ID to select the rows.

    so once the table has loaded it should query the status automatically

    Use initComplete to send the ajax request.

    update the status column of each row once it gets the response.

    Loop through the response data. Use the instituteId in the response data as the row-selector to get the row().data() to update the status.

    status is not part of the row data

    It will be easier to keep the status button updated if you add the status to the row data. It doesn't need to be part of the original data. It can be added after. This way anytime the status changes all you need to do is update the status property of the row data.

    See this example:
    http://live.datatables.net/pojofape/1/edit

    It uses a button to simulate the ajax request. Move it into -option initComplete. The table variable won't be available so you will need to use this.api(). For example:

    initComplete: function () {
      var api = this.api();
      
      var row = api.row();
    

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0

    @kthorngren I am trying your example but I am unable to get the value of 'row.data()' I am getting the value as undefined. here is my sample code
    initComplete: function () {
    console.log(data);
    data.forEach((element) => {
    var id_institutions = element.id_institutions;
    var api = this.api();
    var row = api.row('#' + id_institutions );
    console.log(row.data());
    });
    }

  • kthorngrenkthorngren Posts: 20,141Questions: 26Answers: 4,736
    Answer ✓

    Did you use rowId to set the row id?

    Kevin

  • karankiakarankia Posts: 10Questions: 1Answers: 0
    edited December 2021

    @kthorgen It works finally. Thanks for all your help. Here is what I did. to get the status, first I manually added the status in the response.data oject like
    response.data.forEach((element) => {
    element.status = 'waiting';
    });
    Then in init complete I fetch the status using ajax

            initComplete: function () {
    
                    data.forEach((element) => {
                        var id_institutions = element.id_institutions;
                        var api = this.api();
                        var row = api.row(id_institutions);
                        var newData = row.data();
                        $.ajax({
                            url: '/getInstitutionStatus/' + id_institutions,
                            type: 'GET',
                            dataType: 'json',
                            success: function (response) {
                                newData.status = 'active'
                                row.data(  newData );
                            },error: function (e) {
                                newData.status = 'inactive'
                                row.data(newData);
                            }
                        });
                    });
                }
    
Sign In or Register to comment.