I want to generate data in data table based on JSON response. Following is my JSON response:
{
"alertItems": [
{
"id": "PROD-115388",
"errors": [
"Original Estimate is null",
"id is null"
],
"warnings": [
"Original Estimate is above threshold",
"Story points are above threshold",
"These sub tasks are not defined."
]
},
{
"id": "PROD-112479",
"errors": [],
"warnings": [
"Original Estimate is above threshold",
"Story points are above threshold",
"Estimate is missing for these sub tasks : PROD-112329"
]
},
{
"id": "PROD-108461",
"errors": [],
"warnings": [
"Original Estimate is above threshold",
"Story points are above threshold",
"These sub tasks are not defined : Test Case, BA Documentation Task, QA Design and Execute Task, BA/QA/Dev, BA Testing Task, QA Documentation Task, Elaboration"
]
}
],
"numberOfErrors": 0,
"numberOfWarnings": 10
}
I want to generate Table like following:
I have array of warnings and errors. I want to generate a row for each warning/error against its Id. How can I do that in jQuery datatables?
You may use ajax.dataSrc option to specify callback function that will transform your data to desired format:
const transform = data =>
data.alertItems
.map(({id, errors, warnings}) =>
[...errors.map(error => ({id, type: 'error', reason: error})),
...warnings.map(warning => ({id, type: 'warning', reason:warning}))])
.flat();
In order to group your table rows by matching id's in the first column, you may use rowspan HTML attribute set from within drawCallback function (in order to do that, you'll need to ensure that your table rows sorting order is fixed, so that items with the same id will go sequentially regardless of the sorting/filtering).
So, the complete example (with ajax part commented out, since it's not available within live snippet) might look, like:
//original JSON
const srcJSON = {"alertItems":[{"id":"PROD-115388","errors":["Original Estimate is null","id is null"],"warnings":["Original Estimate is above threshold","Story points are above threshold","These sub tasks are not defined"]},{"id":"PROD-112479","errors":[],"warnings":["OriginalEstimateisabovethreshold","Storypointsareabovethreshold","Estimateismissingforthesesubtasks: PROD-112329"]},{"id":"PROD-108461","errors":[],"warnings":["OriginalEstimateisabovethreshold","Storypointsareabovethreshold","Thesesubtasksarenotdefined: TestCase, BADocumentationTask, QADesignandExecuteTask, BA/QA/Dev, BATestingTask, QADocumentationTask, Elaboration"]}],"numberOfErrors":0,"numberOfWarnings":10};
//proper JSON
const transform = data => data.alertItems.map(({id, errors, warnings}) => [...errors.map(error => ({id, type: 'error', reason: error})),...warnings.map(warning => ({id, type: 'warning', reason:warning}))]).flat();
//datatables init
$('table').DataTable({
/*
ajax: {
url: //url to API endpoint returning original JSON
method: //http method (GET, POST, etc)
dataSrc: transform(data)
}
*/
data: transform(srcJSON), //this one should be dropped once ajax section uncommented
paging: false,
orderFixed: [0,'asc'],
columns: [
{data: 'id', title: 'Story Id'},
{data: 'type', title: 'Type'},
{data: 'reason', title: 'Warning Reason'}
],
//group by first col, using rowspan attribute
drawCallback: function(){
//clean up the view
$('tbody td').attr('rowspan',1).show();
//grab datatable into variable
const table = this.api();
//grab visible, sorted table rows
const rows = table.rows({search:'applied',order:'current'}).nodes();
var groupIdTd = null;
//run through the table rows and set 'rowspan' attribute for matching id's
$.each(rows, function(idx){
const rowspan = Number($(groupIdTd).attr('rowspan') || 1);
idx > 0 && table.cell(groupIdTd).data() == table.cell(this,0).data() ?
($(groupIdTd).attr('rowspan', rowspan+1), $(table.cell(this,0).node()).hide()) :
(groupIdTd = table.cell(this,0).node(), $(groupIdTd).attr('rowspan',1));
});
}
})
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/v/dt/jq-3.3.1/dt-1.10.18/rg-1.1.0/datatables.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/rowgroup/1.1.0/css/rowGroup.dataTables.min.css" />
<script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="https://cdn.datatables.net/v/dt/jq-3.3.1/dt-1.10.18/rg-1.1.0/datatables.min.js"></script>
<script type="application/javascript" src="https://cdn.datatables.net/rowgroup/1.1.0/js/dataTables.rowGroup.min.js"></script>
<script src="test.js"></script>
</head>
<body>
<table></table>
</body>
</html>
Solution is to transform the data before passing it to DataTables using ajax.dataSrc option. Another component of the solution is third-party rowsGroup extension which allows to group rows with identical data.
var table = $('#example').DataTable({
'ajax': {
'url': 'https://api.myjson.com/bins/1b72lv',
'dataSrc': function ( data ) {
var resultData = [];
if(data.hasOwnProperty('alertItems')){
$.each(data.alertItems, function( index, record ) {
$.each(record.errors, function( index, message ) {
resultData.push([ record['id'], 'Error', message ]);
});
$.each(record.warnings, function( index, message ) {
resultData.push([ record['id'], 'Warning', message ]);
});
});
}
return resultData;
}
},
'rowsGroup': [0]
});
See this example for code and demonstration.
See jQuery DataTables: ROWSPAN in table body TBODY for more details on rowsGroup extension.
Related
I'm working on building a KendoGrid that has a variable number of columns that aren't known until runtime. I have code in place that takes the first row of the data and generates the schema and column information, which gets attached to the Kendo DataSource before the grid is wired up. I'm also using a proxy to inject the column field and display name into the template.
What I'm having a hard time dealing with is not knowing how to reference the row data directly, without knowing the property name. I know in a normal kendo template, you could do #= WorkItemId = to get the value itself, but I'm looking for something along the lines of #= model[item.field] # so I can pull the values dynamically.
Is this possible? I've tried this, but that points back to the values I inject with the $.proxy. I've also tried item, model, etc. but nothing seems to give me what I'm looking for.
// kendo.datasource
for (i = 0; i < columns.length; ++i) {
// add template to the cell
columns[i].template = $.proxy(
kendo.template($('#QueueTemplate_Default').html()),
{
columnName: columns[i].title,
fieldName: columns[i].field
}
);
}
// cell template
<script id="QueueTemplate_Default" type="text/x-kendo-template">
#= {{model/this/something}}[item.columnName] #
</script>
// example schema that comes back from the controller
{
"schema": {
"data": "Data",
"total": "Total",
"model": {
"id": "WorkItemId",
"field": {
"WorkItemId": {
"editable": false,
"type": "number"
},
"WorkItem": {
"editable": false,
"type": "string"
},
// edited for brevity
}
}
},
"columns": [
{
"field": "WorkItemId",
"title": "Work Item Id",
"template": null
},
{
"field": "WorkItem",
"title": "Work Item",
"template": null
},
// edited for brevity
]
}
Inside a template, you have data object. In fact you can only access all properties by names like #= PropertyA # because the code is wrapped into a with(data) { ... }(reference) statement. So doing #= PropertyA # is the same as #= data.PropertyA #. Note that with is obsolete.
Example:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Untitled</title>
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.3.1023/styles/kendo.common.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.3.1023/styles/kendo.rtl.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.3.1023/styles/kendo.default.min.css">
<link rel="stylesheet" href="https://kendo.cdn.telerik.com/2019.3.1023/styles/kendo.mobile.all.min.css">
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2019.3.1023/js/angular.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2019.3.1023/js/jszip.min.js"></script>
<script src="https://kendo.cdn.telerik.com/2019.3.1023/js/kendo.all.min.js"></script>
<script>
let data = {
propertyName: 'myProperty',
myProperty: 'myValue'
};
console.log(kendo.template("#= data[data.propertyName] #")(data));
</script>
</head>
<body>
</body>
</html>
Demo
Your case I think can be like:
<script id="QueueTemplate_Default" type="text/x-kendo-template">
#= data[item.columnName] #
</script>
I use jQuery DataTables in my code.
One of my columns has values, like:
AB 05-05-2019
CD 01-05-2019
EF 09-05-2019
When I click this column's header, I want it to get sorted only by using date, not by the prefix ('AB', 'CD', 'EF'). The result should be like:
CD 01-05-2019
AB 05-05-2019
EF 09-05-2019
What I've tried is, inserting a hidden column only with the date and when I sort column with the prefix, I sort my hidden column using JavaScript.
But, is there any proper way by using default configuration of jQuery DataTables?
Assuming, your values are dates in the format 'DD-MM-YYYY' prefixed by two characters and a space, you may built your own little sorting plug-in, with custom sorting function like that:
(first, second) => {
const firstDate = new Date(first.substr(3).split('-').reverse().join('-'));
const secondDate = new Date(second.substr(3).split('-').reverse().join('-'));
return firstDate - secondDate;
};
So, your complete example might look something like this:
//source data
const srcData = [{
id: 1,
value: 'AB 05-05-2019'
}, {
id: 2,
value: 'CD 01-05-2019'
}, {
id: 3,
value: 'EF 09-05-2019'
}
];
//datatable initialization
const dataTable = $('#mytable').DataTable({
dom: 't',
data: srcData,
columns: ['id', 'value'].map(header => ({
title: header,
data: header
})),
columnDefs: [{
type: 'prefixedDate',
targets: 1
}
]
});
//extract Date part of the string
const extractDate = str => new Date(str.substr(3).split('-').reverse().join('-'));
//custom sorting
Object.assign($.fn.DataTable.ext.oSort, {
'prefixedDate-asc': (a, b) => extractDate(a) - extractDate(b),
'prefixedDate-desc': (a, b) => extractDate(b) - extractDate(a),
});
<!doctype html>
<html>
<head>
<script type="application/javascript" src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="application/javascript" src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css">
</head>
<body>
<table id="mytable"></table>
</body>
</html>
Based on the result below , how can an angular for each loop be able to solve that json array of objects format ? The value is title and the id is key. Any Idea? Thank you.
mycode
me.record.questionaires = []
angular.forEach(detail.questionaires, function (value, key) {
me.record.questionaires.push({ "id": key, "title": value })
});
Formated json data (detail.questionaire result)
[
"{'sub_title': 'dsadsa', 'instruction': 'You Must',…elimit': '01:05:19', 'title': 'asdsa', 'id': 133}",
"{'sub_title': 'sdasdsa', 'instruction': None, 'cre…melimit': '05:30:09', 'title': 'asda', 'id': 131}"
]
You need to
Loop over the array
Parse the string as JSON
Push or map the appropriate values into your questionaires array (it's not clear what data you want)
me.record.questionaires = detail.questionaires.map(json => {
let { id, title } = JSON.parse(json)
return { id, title }
})
I had to change your sample formatted JSON a bit because it was giving me console errors. Please see if this helps.
angular
.module("myModule", [])
.controller("myController", function($scope) {
var me ={record: {questionaires: []}};
$scope.me = me;
var detail ={};
detail.questionaires = [
"{'sub_title': 'dsadsa', 'instruction': 'You Must','…elimit': '01:05:19', 'title': 'asdsa', id: 133}",
'{"sub_title": "sdasdsa", "instruction": "None", "cre…melimit": "05:30:09", "title": "asda", "id": 131}'
];
angular.forEach(detail.questionaires, function (value, key) {
var questionaire = JSON.parse(value.replace(/'/g, '"').replace(/id:/g, '"id":'));
me.record.questionaires.push({ "id": questionaire.id, "title": questionaire.title });
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="myModule">
<div ng-controller="myController">
<div><strong>me.record.questionaires:</strong></div>
<div ng-repeat="q in me.record.questionaires">
<div>{{q}}</div>
</div>
</div>
</div>
I am successfully loading JSON data into datatables. But i want to add some processing into specific row. How can I accomplsih this?
I want to add a button
Use the button to send an row ID retrieved from the JSON object into another page for database processing
Here is my JS:
<script>
$.getJSON('../vendor/process/process_vendor.php', function(response) {
var vendButton = '<button>EDIT</button>';
$('#vendorlist').DataTable({
processing: true,
data: response,
columns: [
{data: "CLIENT_ID"},
{data: "CLIENT_NAME"},
{data: "CLIENT_ADDR"},
{data: "CLIENT_LOC"},
{data: "CLIENT_PROV"},
{data: "CLIENT_CONT_PERS"},
{data: "CLIENT_CONT_PH1"},
{data: "CLIENT_CONT_PH2"},
{data: "CLIENT_CONT_FAX"},
vendButton
]
});
window.someGlobalOrWhatever = response.balance;
});
</script>
So far the problem is i cant initialize the vendButton and I couldn't retrieve the specific row ID using CLIENT_ID:
This is the data from JSON response:
[
{
"CLIENT_ID" : "CL0000001",
"CLIENT_NAME" : "ABHIRAMA KRESNA",
"CLIENT_ENT_DATE" : "12-NOV-14",
"CLIENT_ENT_SIGN" : "chrishutagalung",
"CLIENT_CONT_PERS" : null,
"CLIENT_CONT_PH1" : null,
"CLIENT_CONT_PH2" : null,
"CLIENT_CONT_FAX" : null,
"CLIENT_ADDR" : "JL AMARTA BLOK G NO 10 GROGOL",
"CLIENT_LOC" : "SOLO",
"CLIENT_PROV" : null,
"CLIENT_INIT" : "ABK",
"CLIENT_NPWP" : null
}
]
columns is an object describing columns model. You try to simply add a string to it.
Probably, you need to iterate through all objects and add this button to every object.
<script>
$.getJSON('../vendor/process/process_vendor.php', function(response) {
$.each(response, function() {
this.vendButton = "<button data-id='" + this.CLIENT_ID + "'>EDIT</button>";
});
$('#vendorlist').DataTable({
processing: true,
data: response,
columns: [
{data: "CLIENT_ID"},
{data: "CLIENT_NAME"},
{data: "CLIENT_ADDR"},
{data: "CLIENT_LOC"},
{data: "CLIENT_PROV"},
{data: "CLIENT_CONT_PERS"},
{data: "CLIENT_CONT_PH1"},
{data: "CLIENT_CONT_PH2"},
{data: "CLIENT_CONT_FAX"},
{data: "vendButton"}
]
});
window.someGlobalOrWhatever = response.balance;
});
</script>
This will generate another one column with code like this:
<button data-id='123'>EDIT</button>
where 123 is CLIENT_ID for specific row.
Then, on click, you can simply access it like
.click(function()
{
var id = $(this).data('id');
});
You can also use DataTables API to draw this column programmatically.
Refer to an official DataTables example.
i am write some code for cascading drop down with dojo ajax first drop down is static and second one is fetch the data from servlet .. i am using the dijit.form.ComboBox for make dropdown. Dojo provide the Store property in which he store the data and then put it into combobox. in servlet i through the array list to ajax function .. in ajax function i separate the array with comma and strore in variable and then store in the dojo's store property But i am not able to populate the whole string .. it populate only the last value of the string i am using following code
<%#page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" href="dojo/dijit/themes/claro/document.css">
<link rel="stylesheet" href="dojo/dijit/themes/claro/claro.css" />
<script src='dojo/dojo/dojo.js' data-dojo-config=' parseOnLoad: true'></script>
<script>
require(["dojo/parser", "dijit/form/ComboBox","dijit/form/TextBox"]);
function abc(){
var j = document.getElementById('state').value
dojo.xhrPost({
// The URL to request
url: "populate", //servlet name
timeout : 3000 ,
content: {
username: dojo.byId("state").value
},
load: function(result) { // the value in result is like=[Abas Store, Accounts ]
require([
"dojo/ready", "dojo/store/Memory", "dijit/form/ComboBox"
], function(ready, Memory, ComboBox){
var ss=result.split(",");
var i;
for (i=1;i< ss.length ;i++){
var stateStore = new Memory({
data: [ {name:ss[i], id: ss[i]} ]
});
}
ready(function(){
var comboBox = new ComboBox({
id: "stateSelect",
name:"select",
value: "Select",
store: stateStore,
searchAttr: "name"
}, "stateSelect");
});
});
}
});
}
</script>
</head>
<body class="claro">
<select data-dojo-type="dijit.form.ComboBox" id="state" name="state" onchange="abc();">
<option selected >Andaman Nicobar</option>
<option>Andhra Pradesh</option>
<option>Tripura</option>
<option>Uttar Pradesh</option>
<option>Uttaranchal</option>
<option>West Bengal</option>
</select>
<input id="stateSelect" >
</select>
</body>
</html>
please give me solution .. to populate all the value in combobox which is i get from array list
You are building the store in the for loop. Instead, you should build the data array that gets passed into the MemoryStore constructor.
require(["dojo/store/Memory", "dijit/form/ComboBox", "dojo/ready"],
function(Memory, ComboBox, ready){
ready(function) {
dojo.connect(dijit.byId('state'), 'onChange', function() {
var stateSelect = dijit.byId('stateSelect');
if (!stateSelect) {
stateSelect = new ComboBox({
id: "stateSelect",
name: "select",
value: "Select...",
searchAttr: "name"
}, "stateSelect");
}
var ss = 'Abas Store, Accounts';
ss = ss.split(',');
var data = [];
dojo.forEach(ss, function(item, idx) {
data.push({
id: idx,
name: item
});
stateSelect.set('store', new Memory({data: data}));
}); // dojo.connect
}); // ready
}); // require
The working example is at http://jsfiddle.net/cswing/DLNNc/