Ajax request works only the first time and no more after load part of the page

Viewed 128

HTML code:

<div class="table-responsive">
    <table id="dataTable" class="table table-hover table-separated">
        <tbody>
            <tr id="test-1">
                <td class="test">
                    <form action="{{ url('/psy/update-test-status/'.$test->id) }}" method="POST" class="m-0">
                        <select name="status" class="form-control status_select">
                            <option class="text-success" value="active" selected>En ligne</option>
                            <option class="text-warning" value="inactive" >Inactif</option>
                            <option class="text-danger"  value="canceled" >Annulé</option>
                        </select>
                    </form>
                </td>
            </tr>
            <tr id="test-2">
                <td class="test">
                    <form action="{{ url('/psy/update-test-status/'.$test->id) }}" method="POST" class="m-0">
                        <select name="status" class="form-control status_select">
                            <option class="text-success" value="active" selected>En ligne</option>
                            <option class="text-warning" value="inactive" >Inactif</option>
                            <option class="text-danger"  value="canceled" >Annulé</option>
                        </select>
                    </form>
                </td>
            </tr>
            <tr id="test-3">
                <td class="test">
                    <form action="{{ url('/psy/update-test-status/'.$test->id) }}" method="POST" class="m-0">
                        <select name="status" class="form-control status_select">
                            <option class="text-success" value="active" selected>En ligne</option>
                            <option class="text-warning" value="inactive" >Inactif</option>
                            <option class="text-danger"  value="canceled" >Annulé</option>
                        </select>
                    </form>
                </td>
            </tr>
        </tbody>
    </table>
</div>

JavaScript Code:

$(document).ready(function () {

        // change color of selected element according to its value
        function statusSelect(element) {
            if ($(element).val() == 'active') {
                $(element).removeClass('text-warning');
                $(element).removeClass('text-danger');
                $(element).addClass('text-success');
            }
            else if ($(element).val() == 'inactive') {
                $(element).removeClass('text-success');
                $(element).removeClass('text-danger');
                $(element).addClass('text-warning');
            }
            else if ($(element).val() == 'canceled') {
                $(element).removeClass('text-success');
                $(element).removeClass('text-warning');
                $(element).addClass('text-danger');
            }
        }

        // Post form data and load the table again
        function updateTestStatus(element) {
            form = $(element).parent('form');
            tr = form.closest('tr');
            dest_url = form.attr('action');
            $.ajax({
                type:"POST",
                url:dest_url,
                data:form.serialize(),
                dataType: 'json',
                headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
                success: function(data){
                    if($.isEmptyObject(data.errors)){
                        $('#dataTable').load(document.URL +  ' #dataTable');
                        statusSelect($(element));
                    }
                    else {
                        // code...
                    }
                },
                errors: function (data) {
                    // code...
                }
            });
        }

        $('select.status_select').each(function (elem) {
            statusSelect($(this));
        });

        $('select.status_select').on('change', function (e) {
            statusSelect($(this));
            updateTestStatus($(this));
        });
});

Actually, I have at least four problems:

  • I'm not sure about how to order and/or imbricate functions each and on change
  • I can't load only tr element in the ajax success callback: It works fine when loading the full table but when I do $('#dataTable tr#test-1').load(document.URL + ' #dataTable tr#test-1'); it loads the tr inside the previous tr instead of replacing it.
  • The statusSelect method (change color of select selected input text) works the first time but not after Ajax load anymore
  • The updateTestStatus method (Ajax call then reload part of page) works the first time but not anymore after it.

EDIT : 3rd and 4th issues are now solved (The functions in success callback were executed before the load function has finished)

Updated code:

function statusSelect(element) {
            if ($(element).val() == 'active') {
                $(element).removeClass('text-warning');
                $(element).removeClass('text-danger');
                $(element).addClass('text-success');
            }
            else if ($(element).val() == 'inactive') {
                $(element).removeClass('text-success');
                $(element).removeClass('text-danger');
                $(element).addClass('text-warning');
            }
            else if ($(element).val() == 'canceled') {
                $(element).removeClass('text-success');
                $(element).removeClass('text-warning');
                $(element).addClass('text-danger');
            }
        }

        function updateTestStatus(element) {

            form = $(element).parent('form');
            tr = form.closest('tr');
            dest_url = form.attr('action');
            $.ajax({
                type:"POST",
                url:dest_url,
                data:form.serialize(),
                dataType: 'json',
                headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')},
                success: function(data){
                    if($.isEmptyObject(data.errors)){
                        var row_id = tr.attr('id');
                        $('#dataTable #'+row_id).load(document.URL +  ' #dataTable #'+row_id, function() {
                            testStatus();
                        });
                    }
                    else {
                        // code...
                    }
                },
                errors: function (data) {
                    // code...
                }
            });
        }

        function testStatus () {
            $('select.status_select').each(function (elem) {
                statusSelect($(this));
            });

            $('select.status_select').on('change', function (e) {
                statusSelect($(this));
                updateTestStatus($(this));
            });
        }

        testStatus();
    });

I have one issue left: I want to be able to load only <tr> and not all the <table>...

$('#dataTable tr#test-1').load(document.URL + ' #dataTable tr#test-1'); gives me:

<table><tr id="test-1"><tr id="test-1">...</tr></tr></table>

EDIT 2: Solved!

It appears load method "appends inside" and does not "replace" as I believed. This line did the trick:

$('#dataTable #'+row_id).load(document.URL +  ' #dataTable #'+row_id, function() {
    $(this).children(':first').unwrap(); // This one
    testStatus();
});

I was helped by this thread: How can I use jQuery.load to replace a div including the div


Final Edit

The ajax function was sometimes called several times because of the each. Here is how I solved it:

success: function(data){
    if($.isEmptyObject(data.errors)){
        var row_id = tr.attr('id');
        $('#dataTable #'+row_id).load(document.URL +  ' #dataTable #'+row_id, function() {
            $(this).children(':first').unwrap();

            $('#'+row_id+' select.status_select').on('change', function (e) {
                statusSelect($(this));
                updateTestStatus($(this));
            });
            $('select.status_select').each(function (elem) {
                statusSelect($(this));
            });
        });
    }
}
1 Answers

Ajax loads HTML dynamically. JavaScript doesn't work with dynamic HTML as expected.

You can wrap your JavaScript in a function and call it once on load/ready and again on success.

$(document).ready(function () {
   function ajaxFunction (args) {
        $.ajax({
            type:"POST",
            url: url,
            data: data,
            dataType: 'json',
            headers: {header object},
            success: function(data){

            afterAjax (); // call the functions you want to perform again
                // code...
            },
            errors: function (data) {
                // code...
            }
        });
    }
    function afterAjax () {
        // functions to perform again after dynamic HTML load
    }
    afterAjax ()
});
Related