Angular - Datatable click row event - javascript

I am working with AngularJS and angular-datatable and I want to work with the event in a row, I have setup the controller to listen the event but it is not work. My code is :
html
<div class="panel panel-flat">
<div class="panel-heading">
<h6 class="panel-title">Planilla</h6>
</div>
<div class="panel-heading">
<table class="table datatable-basic table-hover" datatable="ng" dt-options="empleadoList.dtOptions" dt-column-defs="empleadoList.dtColumnDefs" >
<thead>
<tr>
<th style="width: 30px;">Nro.</th>
<th>Nombre Completo</th>
<th class="col-md-2">DNI</th>
<th class="col-md-2">Celular</th>
<th class="col-md-2">Teléfono</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="empleado in empleadoList.empleados">
<td style="width: 30px;">{{$index + 1}}</td>
<td> <span class="text-muted"><i class="icon-user"></i>{{empleado.apellidoPaterno}} {{empleado.apellidoMaterno}} {{empleado.nombre}}</span></td>
<td><span class="text-success-600"><span class="status-mark border-blue position-left"></span>{{empleado.dni}}</span></td>
<td><span class="text-success-600"><i class="icon-mobile position-left"></i> {{empleado.celular}}</span></td>
<td><h6 class="text-semibold"><i class="icon-phone position-left"></i> {{empleado.telefono}}</h6></td>
</tr>
</tbody>
</table>
</div>
</div>
controller.js
App.controller('EmpleadoListController', function($scope,$resource,EmpleadoService,DTOptionsBuilder,DTColumnDefBuilder) {
$scope.dtOptions = DTOptionsBuilder.newOptions()
.withDisplayLength(10)
.withOption('bLengthChange', false)
.withPaginationType('full_numbers')
.withOption('rowCallback', rowCallback);
$scope.dtColumnDefs = [
DTColumnDefBuilder.newColumnDef(0),
DTColumnDefBuilder.newColumnDef(1),
DTColumnDefBuilder.newColumnDef(2),
DTColumnDefBuilder.newColumnDef(3),
DTColumnDefBuilder.newColumnDef(4)
];
function rowCallback(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
$('td', nRow).unbind('click');
$('td', nRow).bind('click', function() {
$scope.$apply(function() {
console.log('click row');
});
});
return nRow;
}
EmpleadoService.fetch().then(
function(response){
return $scope.empleadoList = { empleados: response.data};
},
function(errResponse){
console.error('Error while fetching users');
return $q.reject(errResponse);
}
);
});
app.js
'use strict';
var App = angular.module('myApp', ['ngRoute','ngResource','datatables']);
App.config(function($routeProvider) {
var resolveEmpleados = {
empleados: function (EmpleadoService) {
return EmpleadoService.fetch();
}
};
$routeProvider
.when('/planilla', {
controller:'EmpleadoListController as empleadoList',
templateUrl:'static/js/planilla.html',
});
});
Thanks for all.

Since you are using the angular way for rendering, why not use ng-click as well :
<tr ng-repeat="empleado in empleadoList.empleados" ng-click="click(empleado)">
$scope.click = function(empleado) {
console.log(empleado.apellidoPaterno+' clicked')
}

I see you miss function in your code:
function someClickHandler(info) {
vm.message = info.id + ' - ' + info.firstName;
}
function rowCallback(nRow, aData, iDisplayIndex, iDisplayIndexFull) {
// Unbind first in order to avoid any duplicate handler (see https://github.com/l-lin/angular-datatables/issues/87)
$('td', nRow).unbind('click');
$('td', nRow).bind('click', function() {
$scope.$apply(function() {
vm.someClickHandler(aData);
});
});
return nRow;
}
and don't forget this:
vm.someClickHandler = someClickHandler;
you can read document in here
Hope help you.

You were almost there. The row element is accessible from within the row callback function as nRow.
So for instance you can for instance change the colour of the row by toggling the selected class as follows
$scope.$apply(function() {
$(nRow).toggleClass('selected');
// do your stuff with the row here
});
nRow gives you access to the row element.
Then there is aData which gives you an array containing the values of the td or column elements in that row.
$scope.$apply(function() {
console.log(aData);
// do your stuff with the row here
});

Maybe this code can help us:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-row-click-event',
templateUrl: 'row-click-event.component.html'
})
export class RowClickEventComponent implements OnInit {
message = '';
dtOptions: DataTables.Settings = {};
constructor() { }
someClickHandler(info: any): void {
this.message = info.id + ' - ' + info.firstName;
}
ngOnInit(): void {
this.dtOptions = {
ajax: 'data/data.json',
columns: [{
title: 'ID',
data: 'id'
}, {
title: 'First name',
data: 'firstName'
}, {
title: 'Last name',
data: 'lastName'
}],
rowCallback: (row: Node, data: any[] | Object, index: number) => {
const self = this;
// Unbind first in order to avoid any duplicate handler
// (see https://github.com/l-lin/angular-datatables/issues/87)
$('td', row).unbind('click');
$('td', row).bind('click', () => {
self.someClickHandler(data);
});
return row;
}
};
}
}
```
Link where i found this example:
[Link github datatables examples][1]
[1]: https://github.com/l-lin/angular-datatables/blob/master/demo/src/app/advanced/row-click-event.component.ts

Related

Element.DataTable is not a function?

I am using smart admin theme.
I am trying to implement data table but it's show the error
ement.DataTable is not function
my console shows the following error
ERROR TypeError: element.DataTable is not a function
table.ts file code is given below
ngOnInit() {
setTimeout(()=>{this.render()},500);
}
render() {
let element = $(this.el.nativeElement.children[0]);
let options = this.options || {};
let toolbar = "";
if (options.buttons) toolbar += "B";
if (this.paginationLength) toolbar += "l";
if (this.columnsHide) toolbar += "C";
if (typeof options.ajax === "string") {
let url = options.ajax;
options.ajax = {
url: "./../../assets/datatables.standard.json"
// complete: function (xhr) {
//
// }
};
}
options = $.extend(options, {
dom:
"<'dt-toolbar'<'col-xs-12 col-sm-6'f><'col-sm-6 col-xs-12 hidden-xs text-right'" +
toolbar +
">r>" +
"t" +
"<'dt-toolbar-footer'<'col-sm-6 col-xs-12 hidden-xs'i><'col-xs-12 col-sm-6'p>>",
oLanguage: {
sSearch:
"<span class='input-group-addon'><i class='glyphicon glyphicon-search'></i></span> ",
sLengthMenu: "_MENU_"
},
autoWidth: false,
retrieve: true,
responsive: true,
initComplete: (settings, json) => {
element
.parent()
.find(".input-sm")
.removeClass("input-sm")
.addClass("input-md");
}
});
console.log("_dataTable");
console.log(element);
const _dataTable = element.DataTable(options);
if (this.filter) {
// Apply the filter
element.on("keyup change", "thead th input[type=text]", function() {
_dataTable
.column(
$(this)
.parent()
.index() + ":visible"
)
.search(this.value)
.draw();
});
}
if (!toolbar) {
element
.parent()
.find(".dt-toolbar")
.append(
'<div class="text-right"><img src="assets/img/logo.png" alt="SmartAdmin" style="width: 111px; margin-top: 3px; margin-right: 10px;"></div>'
);
}
if (this.detailsFormat) {
let format = this.detailsFormat;
element.on("click", "td.details-control", function() {
var tr = $(this).closest("tr");
var row = _dataTable.row(tr);
if (row.child.isShown()) {
row.child.hide();
tr.removeClass("shown");
} else {
row.child(format(row.data())).show();
tr.addClass("shown");
}
});
}
}
table.html file code is given below
<table class="dataTable responsive {{tableClass}}" width="{{width}}">
<ng-content></ng-content>
</table>
app.component.ts code is given below
public REST_ROOT = 'https://jsonplaceholder.typicode.com';
options = {
dom: "Bfrtip",
ajax: (data, callback, settings) => {
this.http.get(this.REST_ROOT + '/posts')
.pipe(
map((data: any)=>(data.data || data)),
catchError(this.handleError),
)
.subscribe((data) => {
console.log('data from rest endpoint', data);
callback({
aaData: data.slice(0, 100)
})
})
},
columns: [
{ data: "userId" },
{ data: "id" },
{ data: "title" },
{ data: "body" },
]
};
constructor(private http: HttpClient) { }
ngOnInit() {}
private handleError(error: any) {
// In a real world app, we might use a remote logging infrastructure
// We'd also dig deeper into the error to get a better message
let errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg); // log to console instead
return Observable.throw(errMsg);
}
app.component.html code is given below
<div color="blueDark">
<header>
<span class="widget-icon"> <i class="fa fa-table"></i> </span>
<h2>Datatables Rest Demo</h2>
</header>
<div>
<div class="widget-body no-padding">
<app-table [options]="options" tableClass="table table-striped table-bordered table-hover">
<thead>
<tr>
<th [style.width]="'8%'" data-hide="mobile-p">User ID</th>
<th [style.width]="'8%'" data-hide="mobile-p">Post ID</th>
<th>Title</th>
<th data-class="expand">Body</th>
</tr>
</thead>
<tfoot>
<tr>
<th>User ID</th>
<th>Post ID</th>
<th>Title</th>
<th>Body</th>
</tr>
</tfoot>
</app-table>
</div>
</div>
</div>

Is there a way to add button on each row in datatable? [react js]

I want to add 2 buttons [edit and delete] on each row in datatable in react js.
But I couldn't figure out, how to do it;
Please guide me and put some insight into, how to approach or solve this problem.
In order to solve this problem, I tried this code.
But it is couldn't work out.
My code
import Datatable from "../../../common/tables/components/Datatable";
<Datatable
options={{
ajax: "http://demo.weybee.in/react/results.json",
columns: [
{ data: "companycode" },
{ data: "companyname" },
{ data: "firstname" },
{ data: "cityid" },
{ data: "contactno" },
{ data: "workno" },
{ data: <button>Click!</button>}
],
buttons: ["colvis",]
}}
className="table table-striped table-bordered table-hover"
width="100%"
>
<thead>
<tr>
<th data-hide="phone">Code</th>
<th data-class="expand">CompanyName</th>
<th>Firstname</th>
<th data-hide="phone">City</th>
<th data-hide="phone,tablet">Mobile Number</th>
<th data-hide="phone,tablet">Work Number</th>
<th>Actions</th>
</tr>
</thead>
</Datatable>
Actual coding of datatable
import React from "react";
import $ from "jquery";
require("datatables.net-bs");
require("datatables.net-buttons-bs");
require("datatables.net-buttons/js/buttons.colVis.js");
require("datatables.net-buttons/js/buttons.flash.js");
require("datatables.net-buttons/js/buttons.html5.js");
require("datatables.net-buttons/js/buttons.print.js");
require("datatables.net-colreorder-bs");
require("datatables.net-responsive-bs");
require("datatables.net-select-bs");
export default class Datatable extends React.Component {
componentDidMount() {
this.datatable(this.props.data);
}
datatable() {
const element = $(this.refs.table);
let { options } = { ...this.props } || {};
let toolbar = "";
if (options.buttons) toolbar += "B";
if (this.props.paginationLength) toolbar += "l";
if (this.props.columnsHide) toolbar += "C";
if (typeof options.ajax === "string") {
let url = options.ajax;
options.ajax = {
url: url,
complete: function(xhr) {
// AjaxActions.contentLoaded(xhr)
}
};
}
options = {
...options,
...{
dom:
"<'dt-toolbar'<'col-xs-12 col-sm-6'f><'col-sm-6 col-xs-12 hidden-xs text-right'" +
toolbar +
">r>" +
"t" +
"<'dt-toolbar-footer'<'col-sm-6 col-xs-12 hidden-xs'i><'col-xs-12 col-sm-6'p>>",
oLanguage: {
sSearch:
"<span class='input-group-addon input-sm'><i class='glyphicon glyphicon-search'></i></span> ",
sLengthMenu: "_MENU_"
},
autoWidth: true,
retrieve: true,
responsive: true
}
};
const _dataTable = element.DataTable(options);
if (this.props.filter) {
// Apply the filter
element.on("keyup change", "thead th input[type=text]", function() {
_dataTable
.column(
$(this)
.parent()
.index() + ":visible"
)
.search(this.value)
.draw();
});
}
if (!toolbar) {
element
.parent()
.find(".dt-toolbar")
.append(
'<div class="text-right"><img src="assets/img/logo.png" alt="SmartAdmin" style="width: 111px; margin-top: 3px; margin-right: 10px;"></div>'
);
}
if (this.props.detailsFormat) {
const format = this.props.detailsFormat;
element.on("click", "td.details-control", function() {
const tr = $(this).closest("tr");
const row = _dataTable.row(tr);
if (row.child.isShown()) {
row.child.hide();
tr.removeClass("shown");
} else {
row.child(format(row.data())).show();
tr.addClass("shown");
}
});
}
}
render() {
let {
children,
options,
detailsFormat,
paginationLength,
...props
} = this.props;
return (
<table {...props} ref="table">
{children}
</table>
);
}
}
Error
Instead of buttons, object object is displaying [in Action column] on datatable.
in my project I use for this purpose something like this:
let buttonDetails = "<a href='" + urlDetails + "' title='" + titleDetails +"' class='dtDetails' data-target='#remoteModal1' data-toggle='modal' data-backdrop='static'><span class='glyphicon glyphicon-search'></span></a>";
let buttonEdit = "<a href='"+urlEdit+"' title='"+titleEdit+"' class='dtEdit' data-target='#remoteModal' data-toggle='modal' data-backdrop='static'><span class='glyphicon glyphicon-pencil'></span></a>";
let buttonDelete = "<a href='" + urlDelete + "' title='" + titleDelete +"' class='dtDelete' data-target='#remoteModal1' data-toggle='modal' data-backdrop='static'><span class='glyphicon glyphicon-remove'></span></a>";
...
"columnDefs": [
...
{
"targets": [2],
"width": miCustomWidth,
"className": "center",
"data": function (d) {
return buttonDetails.replace("ID_X", d.rowIdField) + " " + buttonEdit.replace("ID_X", d.rowIdField) + " " + buttonDelete.replace("ID_X", d.rowIdField);
}
}
...
]

jQuery Datatable cell not updating

I have a table that I am using jQuery Datatables with.
Picture:
Scenario:
As you can see in the picture, there is a Delete link. When that link is clicked, a modal pop-up will show asking the user if they really want to delete that item. If yes, delete.. if no.. cancel out of the modal.
What I want:
When a user decides to delete an item and confirms it.. I would like to change the status of that item to "Deleted", via ajax. I am able to change the value, but that value does not show in the table. I have researched this for a couple of days now, but nothing seems to work.
My Code
<table id="Item-Table" class="table table-bordered">
<thead>
<tr>
<th class="text-center">
#Html.DisplayNameFor(model => model.AssetTag)
</th>
<th class="text-center">
#Html.DisplayNameFor(model => model.codeMakeModel.MakeModel)
</th>
<th class="text-center">
#Html.DisplayNameFor(model => model.codeStatu.Status)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr class="text-center">
<td>
#Html.ActionLink(item.AssetTag, "Edit", new { id = item.Id })
</td>
<td>
#Html.DisplayFor(modelItem => item.codeMakeModel.MakeModel)
</td>
<td class="changeStatus">
#Html.DisplayFor(modelItem => item.codeStatu.Status)
</td>
<td>
Delete
</td>
</tr>
}
</tbody>
</table>
#section scripts{
<script>
var settings = {};
settings.baseUri = '#Request.ApplicationPath';
var infoGetUrl = "";
if (settings.baseUri === "/projectonservername") {
infoGetUrl = settings.baseUri + "/api/itemsapi/";
} else {
infoGetUrl = settings.baseUri + "api/itemsapi/";
}
$(document).ready(function () {
var itemsTable = $("#Item-Table").DataTable({
"aoColumnDefs": [
{ "bSortable": false, "aTargets": [3] },
{ "bSearchable": false, "aTargets": [3] }
]
});
$("#Item-Table").on("click",
".js-item-delete",
function() {
var link = $(this);
bootbox.confirm({
title: "Delete Item?",
message: "Are you sure you want to delete this item?",
buttons: {
cancel: {
label: '<i class="fa fa-times"></i> Cancel'
},
confirm: {
label: '<i class="fa fa-check"></i> Confirm'
}
},
callback: function(result) {
if (result) {
toastr.options = {
timeOut: 5000
}
$.ajax({
url: infoGetUrl + link.data("item-id"),
method: "DELETE",
success: function (result) {
//itemsTable.cell(itemsTable.row(this), 2).data("Deleted");
//itemsTable.draw();
//itemsTable.reload();
console.log(itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data());
itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data("Deleted").draw();
console.log(itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data());
toastr.success("Item successfully deleted");
},
error: function(jqXHR, textStatus, errorThrown) {
var status = capitalizeFirstLetter(textStatus);
console.log(jqXHR);
toastr.error(status + " - " + errorThrown, "Sorry, something went wrong.");
}
});
}
}
});
});
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
})
</script>
}
What I am Receiving
In the above code, specifically these lines:
console.log(itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data());
itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data("Deleted").draw();
console.log(itemsTable.cell(itemsTable.row(this), $('.changeStatus')).data());
I am logging the value of the cell before I update that cell value, then changing the cell value, then logging the new/updated cell value.
Here is what I am receiving in the console:
But the table is not updating, or rather.. redrawing itself to show deleted.. the only way for it show deleted is to refresh the page which defeats the purpose of ajax..
How do I get the table to update the cell value without a page refresh?
Any help is appreciated.
I was able to answer this myself with some help of DavidDomain in the comments.
He suggested that I could possibly be selecting an incorrect row. So that gave me the idea to get the row at the start of this by adding:
$("#Item-Table").on("click",
".js-item-delete",
function() {
var link = $(this);
var row = $(this).parents("tr"); // get row element
Then set the cell data using that variable like so:
itemsTable.cell(itemsTable.row(row), $('.changeStatus')).data("Deleted").draw();
This worked and successfully drew the table with the updated value.

Angular ng-repeat change values

I'm doing a table with angular using ng-repeat. And all it's work but in some cases the json return me some data like PA-AC-DE and i want to change this in the table in Pending, Active and deactivate. And i don't know how i can do it.
<table class="table table-bordered table-hover table-striped dataTable no-footer" data-sort-name="name" data-sort-order="desc">
<tr role="row" class="info text-center">
<th ng-click="order('msisdn')">Número Teléfono</th>
<th ng-click="order('icc')">ICC</th>
<!--th>IMEI</th-->
<th ng-click="order('ActivationStatus')">Estado</th>
<th ng-click="order('sitename')">Instalación</th>
<th ng-click="order('siteaddress')">Dirección</th>
<th ng-click="order('sitecity')">Ciudad</th>
<th ng-click="order('sitezip')">Código Postal</th>
<th ng-click="order('phonedesc')">Modelo Teléfono</th>
<th ng-click="order('ContractingMode')">VBP</th>
</tr>
<tr class=" text-center" ng-repeat-start="object in filteredsites = (objects | filter:searchText) | filter:tableFilter| orderBy:predicate:reverse" ng-click="showDetails = ! showDetails">
<td>{{object.msisdn}}</td>
<td>{{object.icc}}</td>
<td>{{object.ActivationStatus}}</td>
<td>{{object.sitename}}</td>
<td>{{object.siteaddress}}</td>
<td>{{object.sitecity}}</td>
<td>{{object.sitezip}}</td>
<td>{{object.phonedesc}}</td>
<td>{{ object.ContractingMode ? 'Yes': 'No'}}</td>
</tr>
</table>
You can use a filter
{{object.ActivationStatus | statusFilter}}
and statusFilter will be like:
angular.module('module', []).filter('statusFilter', function() {
return function(input) {
//switch-case
};});
You could use ng-show to show text depending on the value returned from your API like so:
<td><span ng-show="object.ActivationStatus=='AC'">Active</span><span ng-show="object.ActivationStatus=='PA'">Other Label</span></td>
and so on.
With a custom filter method it would look like in the demo below or here at jsfiddle.
But also a getter function with the same code would be OK.
angular.module('demoApp', [])
.controller('mainController', function() {
this.data = [
{status:'AC'},
{status:'AC'},
{status:'DE'},
{status:'PA'},
];
})
.filter('filterStatus', function() {
var labels = {
AC: 'active',
DE: 'deactive',
PA: 'pending'
};
return function(input) {
return labels[input];
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="demoApp" ng-controller="mainController as ctrl">
<ul>
<li ng-repeat="row in ctrl.data">
status: {{row.status | filterStatus}}
</li>
</ul>
</div>
Based on AWolf answer with filter, here is using a function in the controller:
http://jsfiddle.net/f4bfzjct/
angular.module('demoApp', [])
.controller('mainController', function() {
var vm = this;
vm.data = [
{status:'AC'},
{status:'AC'},
{status:'DE'},
{status:'PA'},
];
vm.getFullStatus = function(value) {
var labels = {
AC: 'active',
DE: 'deactive',
PA: 'pending'
};
return labels[value];
}
});
<div ng-app="demoApp" ng-controller="mainController as ctrl">
<ul>
<li ng-repeat="row in ctrl.data">
status: {{ctrl.getFullStatus(row.status)}}
</li>
</ul>
</div>
I think you should create a filter in your module:
ngModule.filter('phoneNumberStatus', function() {
statuses = {
AC: 'Active'
DE: 'Unactive'
}
return function(value) {
return statuses[value] || "Unknown"
}
})
and then use it in your template:
<td>{{ object.ActivationStatus | phoneNumberStatus }}</td>
This way will enable you to reused this filter in any template, avoiding duplicated code.
You can create a javascript function that returns your desired value:
$scope.getFullActivationText = function(input) {
if (input === 'PA') {
return 'Pending';
}
else if (input === 'AC') {
return 'Active';
}
else if (input === 'DE') {
return 'Deactivate';
}
}
Now you can keep everything the same in your HTML but replace:
<td>{{object.ActivationStatus}}</td>
into
<td>getFullActivationText(object.ActivationStatus)</td>

KNockoutJS with jQuery datatables, bound rows are not updated properly

Here's JS code:
function ProductViewModel() {
// Init.
var self = this;
self.products = ko.observableArray();
self.singleProduct = ko.observable();
var mappedProducts;
// Initialize table here.
$.getJSON("/admin/test", function(allData) {
mappedProducts = $.map(allData, function(item) { return new Product(item);});
self.products(mappedProducts);
self.oTable = $('#products-table').dataTable( {
"aoColumns": [
{ "bSortable": false, "mDataProp": null, sDefaultContent: '' },
{"mData": "name"},
{"mData": "dealer"},
{"mData": "cost"},
{"mData": "price"},
{ "bSortable": false, sDefaultContent: '' }
],
});
});
// Here i'm using the basic switch pattern, as from KO tutorials.
// This is intended for showing a single product form.
self.edit = function(product) {
self.singleProduct(product);
}
// This is intended to hide form and show list back.
self.list = function() {
self.singleProduct(null);
}
// This is the form save handler, actually does nothing
// but switch the view back on list.
self.doEdit = function(product) {
self.list();
}
}
// My model.
function Product(item) {
this.name = ko.observable(item.name);
this.dealer = ko.observable(item.dealer);
this.cost = ko.observable(item.cost);
this.price = ko.observable(item.price);
this.picture = ko.observable();
}
Here's my markup:
<table id="products-table" class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th>Pic</th>
<th>Name</th>
<th>Dealer</th>
<th>Cost</th>
<th>Price</th>
<th>Actions</th>
</tr>
</thead>
<tbody data-bind="foreach: $parent.products">
<tr>
<td><span data-bind='ifnot: picture'>-</span></td>
<td><a data-bind="text: name"></a></td>
<td><span data-bind='text: dealer'></span></td>
<td><span data-bind='text: cost'></span></td>
<td><span data-bind='text: price'></span></td>
<td>
<button data-bind='click: $root.edit'><i class='icon-pencil'></i>
</button>
</td>
</tr>
</tbody>
</table>
When i do click on the edit button, triggering the $root.edit handler, a form is shown because of a
<div data-bind='with: singleProduct'>
binding i have made. Inside this binding i have a form, with a
<input data-bind="value: name" type="text" id="" placeholder="Name"
> class="col-xs-10 col-sm-5">
field.
Problem: When i edit the value in the input field, the relative row in the datatable is not updated. I have tried a basic table without the datatables plugin and it does work, meaning that if i change value, the row in the table is properly updated.
What's wrong here?
== EDIT ==
I found out that moving the bind point to the table TD fixed the problem, though still i can't figure out why.
<tr>
<td data-bind="text: name"></td>
<!-- More columns... -->
</tr>
The above code is working properly now. Why ?
== EDIT2 ==
Now that i fixed first issue, comes the second. I implemented my "save new" method like so
self.doAdd = function(product) {
$.ajax("/product/", {
data: ko.toJSON({ product: product }),
type: "post", contentType: "application/json",
success: function(result) { alert('ehh'); }
}).then(function(){
self.products.push(product); // <--- Look at this!
self.list();
});
}
The self.products.push(product); in the success handler is properly updating my products observable. Then, a new row is automatically added to my table, and this is the good news.
Bad news is that datatables controls, such search field or clickable sorting arrows, disappear as soon as i push the new product in the array. Why so!?
Did you ever resolve this?
I've been having similar issues for ages.
In the end my fix was to map all my entities using ko.mapping.fromJS(entity) - this then hooked up all the required dependencies and ensured that any changes flowed through my model.
http://jsfiddle.net/zachpainter77/4tLabu56/
ko.bindingHandlers.DataTablesForEach = {
init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
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, allBindingsAccessor, viewModel, bindingContext) {
var value = ko.unwrap(valueAccessor()),
key = "DataTablesForEach_Initialized";
var newValue = function () {
return {
data: value.data || value,
beforeRenderAll: function (el, index, data) {
if (ko.utils.domData.get(element, key)) {
$(element).closest('table').DataTable().destroy();
}
},
afterRenderAll: function (el, index, data) {
$(element).closest('table').DataTable(value.options);
}
};
};
ko.bindingHandlers.foreach.update(element, newValue, allBindingsAccessor, viewModel, bindingContext);
//if we have not previously marked this as initialized and there is currently items in the array, then cache on the element that it has been initialized
if (!ko.utils.domData.get(element, key) && (value.data || value.length)) {
ko.utils.domData.set(element, key, true);
}
return { controlsDescendantBindings: true };
}
};
https://rawgit.com/zachpainter77/zach-knockout.js/master/zach-knockout.debug.js

Categories

Resources