KnockoutJS & jQuery Datatable custom binding (jQueryUI)

a custom knockout binding works on vanilla 3.4 knockout

by KANDR101

HTML

<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/responsive/2.2.3/css/responsive.bootstrap4.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css" rel="stylesheet">

<!-- <script src="https://code.jquery.com/jquery-3.3.1.js"></script> -->
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.3/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/responsive/2.2.3/js/responsive.bootstrap4.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.3.5/knockout.mapping.js"></script>

<div class="container">
  <table class="table table-striped table-bordered nowrap small" id="vehicleSearchGrid" style="width:100%">
    <thead>
      <tr>
        <th class="d-none">Select</th>
        <th>Full Name</th>
        <th>Position</th>
        <th>Office</th>
        <th>Start Date</th>
        <th>Salary</th>
        <th></th>
      </tr>
    </thead>
    
    <tbody data-bind="
        dataTablesForEach : {
            data: employees,
            options: { 
       ...

CSS

/* Ensure that the demo table scrolls */

td.control.control-right::before,
th.control.control-right::before,
td.control.control-left::before,
th.control.control-left::before {
    top: 49% !important;
    left: 49% !important;
    height: 15px !important;
    width: 15px !important;
    line-height: 15px !important;
}

.table>tbody>tr.text-vcenter>td,
.table>tbody>tr.text-vcenter>th,
.table>tbody>tr>td.text-vcenter,
.table>tbody>tr>th.text-vcenter {
    vertical-align: middle !important;
}

.table>tbody>tr>td.action-btn .dropdown-btn {
    position: relative !important;
    cursor: pointer;
    padding: 0 0.75rem !important;
}

.table>tbody>tr>td.action-btn .dropdown-btn i {
    font-weight: 900;
    font-family: "Font Awesome 5 Free";
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    display: inline-block;
    font-style: normal;
    font-variant: normal;
    text-rendering: auto;
    line-height: 3;
}

.table>tbody>tr>td.action-btn .dropdown-btn i::before {
    content: "\f141";
    top: 50%;
    left: 50%;
    height: 23px;
    width: 25px;
    margin-top: -12px;
    margin-left: -12px;
    display: block;
    position: absolute;
    color: white;
    /* border: 2px solid white; */
    border-radius: 4px;
    box-sizing: content-box;
    text-align: center;
    text-indent: 0 !important;
    line-height: 23px;
}

td a.cmp-status {
    font-size: 1.33333em;
    line-height: .75em;
    vertical-align: -.0667em;
    font-size: 1.33333em;
    line-height: .75em;
    vertical-align: -.0667em;
    font-weight: 900;
    font-family: "Font Awesome 5 Free";
    -moz-osx-font-smoothing: grayscale;
    -webkit-font-smoothing: antialiased;
    display: inline-block;
    font-style: normal;
    font-variant: normal;
    text-rendering: auto;
    text-decoration: none;
    cursor: default;
}

td a.cmp-status.text-success {
    text-decoration: underline !important;
    cursor: pointer !important;
}

td a.cmp-status>b {
    display: none;
}

JavaScript

ko.bindingHandlers.dataTablesForEach = {
  page: 0,
  init: function(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
    var binding = ko.utils.unwrapObservable(valueAccessor());

    ko.unwrap(binding.data);

    if (binding.options.paging) {
      binding.data.subscribe(function(changes) {
        var table = $(element).closest('table').DataTable();
        ko.bindingHandlers.dataTablesForEach.page = table.page();
        table.destroy();
      }, null, 'arrayChange');
    }

    var nodes = Array.prototype.slice.call(element.childNodes, 0);
    ko.utils.arrayForEach(nodes, function(node) {
      if (node && node.nodeType !== 1) {
        node.parentNode.removeChild(node);
      }
    });

    return ko.bindingHandlers.foreach.init(element, valueAccessor, allBindingsAccessor, viewModel, bindingContext);
  },
  update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    var binding = ko.utils.unwrapObservable(valueAccessor()),
      key = 'DataTablesForEach_Initialized';

    ko.unwrap(binding.data);

    var table;
    if (!binding.options.paging) {
      table = $(element).closest('table').DataTable();
      table.destroy();
    }

    ko.bindingHandlers.foreach.update(element, valueAccessor, allBindings, viewModel, bindingContext);

    table = $(element).closest('table').DataTable(binding.options);

    if (binding.options.paging) {
      if (table.page.info().pages - ko.bindingHandlers.dataTablesForEach.page === 0) {
        table.page(--ko.bindingHandlers.dataTablesForEach.page).draw(false);
      } else {
        table.page(ko.bindingHandlers.dataTablesForEach.page).draw(false);
      }
    }

    if (!ko.utils.domData.get(element, key) && (binding.data || binding.length)) {
      ko.utils.domData.set(element, key, true);
    }

    return {
      controlsDescendantBindings: true
    };
    
  }
};

var ViewModel = function() {
  this.employees = ko.observableArray([{
    "name": "Airi Satou",
   ...