Search code examples
javascriptjquerytwitter-bootstrapdatatablesbootstrap-switch

Bootstrap switch inside datatables plugin with ajax call catch event


I'm using datatables plugin and I have a problem with bootstrap switch. This is my javascript code, where I create a switch with the value retrieved from ajax call:

$(document).ready(function() {
    if ( ! $.fn.DataTable.isDataTable( '#usersTable' ) ) {
        userTable = $('#usersTable').DataTable({
            responsive: true,
            //fix problem with responsive table
            "autoWidth": false,
            "ajax": "table",
            "columns": [
                        { "data": "username" },
                        { data: "enabled", render: function ( data, type, row ) {
                            if (data) {
                                return '<input data="username" type="checkbox" name="my-checkbox" checked>';
                            }
                            else {
                                return '<input data="username" type="checkbox" name="my-checkbox">';
                            }
                        }   
                        },
                        { "data": "role.role"},
                        { "data": "clientVersion.name" },
                        {
                            data: null,
                            className: "center",
                            defaultContent: '<button type="button" class="btn btn-danger" id="deleteLicense" data-toggle="modal" th:attr="data-href=${license.idClientLicense}" data-target="#deleteLicenseModal">Delete</button>'
                        }
                        ],
                        "fnDrawCallback": function() {
                            //Initialize checkbos for enable/disable user
                            $("[name='my-checkbox']").bootstrapSwitch({size: "small", onColor:"success", offColor:"danger"});
                        }
        });
    }
    else {
        userTable.ajax.url("table").load();
    }

    $('input[name="my-checkbox"]').on('switchChange.bootstrapSwitch', function(event, state) {
        //CSRF attribute for spring security
        var token = $("meta[name='_csrf']").attr("content");
        var header = $("meta[name='_csrf_header']").attr("content");
        $.ajax({
            type : "POST",
            url : "status"+(this).attr("data"),
            data : form.serialize(),
            beforeSend:function(xhr) {
                xhr.setRequestHeader(header, token);
            },  
//          all right with rest call
            success : function(data) {  
//              No exception occurred
                if (data.status==true){ 
//                  Also the field are right(for e.g. form value)
                    if(data.success==true){
//                      il risultato sta in data.result
//                      window.location.reload(true);
                        //reset select 2 choise because it can set with old user who no longer exist 
//                      reload only the tag with id carsTable, so only the table

                    }
                    else{
//                      code if there are some error into form for example
                    }
                } else {
//                  code exception
                    notifyMessage(data.result, 'error');
                }
            },
//          error during rest call
            error : function(data) {
                window.location.href = "/ATS/500";
            }
        });
    }); 
});

and this is HTML code:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org"
    xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4"
    xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Administration users</title>
<!-- Tell the browser to be responsive to screen width -->
<meta
    content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
    name="viewport">
<!-- Spring csrf  -->
<meta name="_csrf" th:content="${_csrf.token}" />
<!-- default header name is X-CSRF-TOKEN -->
<meta name="_csrf_header" th:content="${_csrf.headerName}" />
<!-- Bootstrap Core CSS -->
<link th:href="@{/static/assets/bootstrap/css/bootstrap.css}"
    rel="stylesheet">
<!-- Font Awesome -->
<link rel="stylesheet"
    th:href="@{/static/assets/component/font-awesome-4.4.0/css/font-awesome.min.css}">
<!-- Ionicons -->
<link rel="stylesheet"
    href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
<!-- DataTables -->
<link rel="stylesheet"
    th:href="@{/static/assets/plugins/datatables/dataTables.bootstrap.css}">
<link rel="stylesheet"
    th:href="@{/static/assets/plugins/datatables/extensions/Responsive/css/responsive.bootstrap.min.css}">
<!-- Theme style -->
<link rel="stylesheet"
    th:href="@{/static/assets/dist/css/AdminLTE.min.css}">
<!-- AdminLTE Skins. Choose a skin from the css/skins
         folder instead of downloading all of them to reduce the load. -->
<link rel="stylesheet"
    th:href="@{/static/assets/dist/css/skins/_all-skins.min.css}">
<!-- Select2 -->
<link rel="stylesheet"
    th:href="@{/static/assets/plugins/select2/select2.min.css}">
<!-- Bootstrap switch -->
<link rel="stylesheet"
    th:href="@{/static/assets/plugins/bootstrap-switch/css/bootstrap-switch.min.css}">
<!-- jQuery 2.1.4 -->
<script th:src="@{/static/assets/plugins/jQuery/jQuery-2.1.4.min.js}"
    type="text/javascript"></script>
<!-- Bootstrap 3.3.5 -->
<script th:src="@{/static/assets/bootstrap/js/bootstrap.min.js}"
    type="text/javascript"></script>
<!-- DataTables -->
<script type="text/javascript"
    th:src="@{/static/assets/plugins/datatables/jquery.dataTables.min.js}"></script>
<script type="text/javascript"
    th:src="@{/static/assets/plugins/datatables/dataTables.bootstrap.min.js}"></script>
<script type="text/javascript"
    th:src="@{/static/assets/plugins/datatables/extensions/Responsive/js/dataTables.responsive.min.js}"></script>
<script type="text/javascript"
    th:src="@{/static/assets/plugins/datatables/extensions/Responsive/js/responsive.bootstrap.min.js}"></script>
<!-- page script -->
<!-- Slimscroll -->
<script type="text/javascript"
    th:src="@{/static/assets/plugins/slimScroll/jquery.slimscroll.min.js}"></script>
<!-- FastClick -->
<script type="text/javascript"
    th:src="@{/static/assets/plugins/fastclick/fastclick.min.js}"></script>
<!-- Bootstrap-growl -->
<script type="text/javascript"
    th:src="@{/static/assets/plugins/notify/jquery.bootstrap-growl.js}"></script>
<!-- AdminLTE App -->
<script type="text/javascript"
    th:src="@{/static/assets/dist/js/app.min.js}"></script>
<!-- AdminLTE for demo purposes -->
<script type="text/javascript"
    th:src="@{/static/assets/dist/js/demo.js}"></script>
<!-- Select2 -->
<script type="text/javascript"
    th:src="@{/static/assets/plugins/select2/select2.full.min.js}"></script>
<!-- Bootstrap switch -->
<script type="text/javascript"
    th:src="@{/static/assets/plugins/bootstrap-switch/js/bootstrap-switch.min.js}"></script>
<script type="text/javascript" th:src="@{/static/assets/js/user.js}"></script>
</head>
<body class="hold-transition skin-blue sidebar-mini">
    <div class="wrapper">
        <!-- Header nd menu fragment -->
        <div th:replace="../fragments/dashboard-header :: dashboard-header"></div>
        <!-- Content Wrapper. Contains page content -->
        <div class="content-wrapper">
            <!-- Content Header (Page header) -->
            <section class="content-header">
                <h1>Administration</h1>
                <ol class="breadcrumb">
                    <li><a th:href="@{/}"><i class="fa fa-dashboard"></i> Home
                    </a></li>
                    <li class="active">User</li>
                </ol>
            </section>
            <!-- Main content -->
            <section class="content">
                <div class="row">
                    <div class="col-xs-12">
                        <div class="box">
                            <div class="box-header">
                                <h3 class="box-title">Users</h3>
                            </div>
                            <!-- /.box-header -->
                            <div class="box-body">
                                <!-- -Users table -->
                                <table id="usersTable"
                                    class="table table-bordered table-striped">
                                    <thead>
                                        <tr>
                                            <th>Username</th>
                                            <th>Enable</th>
                                            <th>Role</th>
                                            <th>Version</th>
                                            <th>Delete</th>
                                        </tr>
                                    </thead>
                                </table>
                                <!-- Create two equals button because when I am on desktop I show the text add fleet otherwise the + and the tooltip. 
                                This is need because otherwise the text goes out the button -->
                                <button id="addUserButton" type="button"
                                    class="btn btn-primary visible-lg col-lg-1 col-lg-offset-11"
                                    data-toggle="modal" data-target="#addUserModal">Add
                                    user</button>
                                <button id="addlicenseButton" type="button"
                                    class="btn btn-primary hidden-lg col-xs-1 col-xs-offset-11"
                                    data-toggle="modal" data-target="#addUserModal">
                                    <span class="glyphicon glyphicon-plus" data-toggle="tooltip"
                                        title="Add user"></span>
                                </button>
                            </div>
                        </div>
                    </div>
                    <!-- /.col -->
                </div>
                <!-- /.row -->
            </section>
            <!-- /.content -->
        </div>
    </div>
</body>
</html>

I read several questions and answer but I think that my problem is linked to "fnDrawCallback": function() because I tried all the solutions and None worked. Might be that the switch isn't correctly setted? This is the table enter image description here


Solution

  • CAUSE

    Pages other than first do not exist in DOM at the time of initialization, that is why your handler never gets called.

    SOLUTION

    You need to use event delegation by providing selector as a second argument in on() call, see example below:

    $('#usersTable').on('switchChange.bootstrapSwitch', 'input[name="my-checkbox"]', function(event, state) {
       // ... skipped ...
    });
    

    From jQuery on() method documentation:

    Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.

    See "Direct and delegated events" in jQuery on() method documentation and jQuery DataTables – Why click event handler does not work for more information.

    NOTES

    Custom controls and Responsive extension require special handling. If column containing custom control becomes hidden or visible, it should be re-initialized. See jQuery DataTables – Responsive extension and custom controls for more information.