Currently we are doing this to draw the columns for a server side DataTable for 2 different users, we were able to hide the column headers using razor code to only draw them when the user is an admin or group admin. However when it comes to drawing the data we are having an issue with the following:
function getTableColumns() {
var allowedToDelete = #(User.IsInRole("SysAdmin") || GroupManager.IsUserGroupAdmin(Model.GroupId, User.FindFirst(ClaimTypes.NameIdentifier).Value) ? "true" : "false");
if (allowedToDelete) {
return [{ "defaultContent": "" },
{ "data": "deadlineDate", "name": "DeadlineDate" },
{ "data": "priority", "name": "Priority" },
{ "data": "jobNumber", "name": "JobNumber" },
{ "data": "project", "name": "Project" },
{ "data": "description", "name": "Description" },
{ "data": "reference", "name": "Reference" },
{ "data": "subReference", "name": "SubReference" },
{ "data": "employee", "name": "Employee" },
{ "data": "allocatedTo", "name": "AllocatedTo" },
{
"render": function (data, type, full, meta) {
return "<i title ='Archive Item' class='fa fa-archive table-icon-view' onclick='archiveJob(\""
+ full.groupId + "\",\"" + full.id + "\")'></i>";
}
},
{
"render": function (data, type, full, meta) {
return "<i title ='Edit' class='fa fa-pencil table-icon-edit' onclick='editJob(\""
+ full.groupId + "\",\"" + full.id + "\")'></i>";
}
},
{
"render": function (data, type, full, meta) {
return "<i title ='Delete' class='fa fa-trash table-icon-delete' onclick='showDeleteModal(\""
+ full.groupId + "\",\"" + full.id + "\")'></i>";
}
},
{ "data": "issueDate" },
{ "data": "startDate" },
{ "data": "createdBy" },
{ "data": "createdDate" },
{ "data": "notes" }];
} else {
return [{ "defaultContent": "" },
{ "data": "deadlineDate", "name": "DeadlineDate" },
{ "data": "priority", "name": "Priority" },
{ "data": "jobNumber", "name": "JobNumber" },
{ "data": "project", "name": "Project" },
{ "data": "description", "name": "Description" },
{ "data": "reference", "name": "Reference" },
{ "data": "subReference", "name": "SubReference" },
{ "data": "employee", "name": "Employee" },
{ "data": "allocatedTo", "name": "AllocatedTo" },
{
"render": function (data, type, full, meta) {
return "<i title ='Edit' class='fa fa-pencil table-icon-edit' onclick='editJob(\""
+ full.groupId + "\",\"" + full.id + "\")'></i>";
}
},
{ "data": "issueDate" },
{ "data": "startDate" },
{ "data": "createdBy" },
{ "data": "createdDate" },
{ "data": "notes" }];
}
}
Is there a way to optimise this so that we don't have to repeat the code just to hide 2 icon links?
You could use the columns.visible option to display/hide the column accordingly.
Additionally, it might be worth looking at Reusable renderers to avoid some of the repetition with the rendering functions.
Creating such a rendering function may look like this:
$.fn.dataTable.render.icon = function ( title, icon, func) {
return function ( data, type, row ) {
return "<i title ='" + title + "' class='fa " + icon + "' onclick='" + func + "(\""
+ row.groupId + "\",\"" + row.id + "\")'></i>";
}
};
You could then use this as follows:
{
//Column visibility
visible: allowedToDelete,
//Reusable renderer
render: $.fn.dataTable.render.icon('Archive Item', 'fa-archive table-icon-view', 'archiveJob')
},
{
visible: allowedToDelete,
render: $.fn.dataTable.render.icon('Edit', 'fa-pencil table-icon-edit', 'editJob')
},
{
visible: allowedToDelete,
render: $.fn.dataTable.render.icon('Delete', 'fa-trash table-icon-delete', 'showDeleteModal')
},
You could have the default array be defined in a variable, and push the 2 icon links into it inside the if, before returning:
function getTableColumns() {
var allowedToDelete = #(User.IsInRole("SysAdmin") || GroupManager.IsUserGroupAdmin(Model.GroupId, User.FindFirst(ClaimTypes.NameIdentifier).Value) ? "true" : "false");
var dataArray = [{ "defaultContent": "" },
{ "data": "deadlineDate", "name": "DeadlineDate" },
{ "data": "priority", "name": "Priority" },
{ "data": "jobNumber", "name": "JobNumber" },
{ "data": "project", "name": "Project" },
{ "data": "description", "name": "Description" },
{ "data": "reference", "name": "Reference" },
{ "data": "subReference", "name": "SubReference" },
{ "data": "employee", "name": "Employee" },
{ "data": "allocatedTo", "name": "AllocatedTo" },
{
"render": function (data, type, full, meta) {
return "<i title ='Edit' class='fa fa-pencil table-icon-edit' onclick='editJob(\""
+ full.groupId + "\",\"" + full.id + "\")'></i>";
}
},
{ "data": "issueDate" },
{ "data": "startDate" },
{ "data": "createdBy" },
{ "data": "createdDate" },
{ "data": "notes" }];
if (allowedToDelete) {
return dataArray.Concat([{
"render": function (data, type, full, meta) {
return "<i title ='Edit' class='fa fa-pencil table-icon-edit' onclick='editJob(\""
+ full.groupId + "\",\"" + full.id + "\")'></i>";
}
},
{
"render": function (data, type, full, meta) {
return "<i title ='Delete' class='fa fa-trash table-icon-delete' onclick='showDeleteModal(\""
+ full.groupId + "\",\"" + full.id + "\")'></i>";
}
}]).ToArray();
} else {
return dataArray;
}
}
Related
I have an array of objects like below. Each object has permanent key 'type' and depending on the 'type', new keys are added.
So if type: 'text', we have a new key 'text'.
If type: 'notText', we have a new key 'attrs'.
arrayOfObj = [
{
"type": "text",
"text": "="
},
{
"type": "text",
"text": " "
},
{
"type": "text",
"text": "S"
},
{
"type": "text",
"text": "O"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
},
{
"type": "text",
"text": "H"
},
{
"type": "text",
"text": "E"
},
{
"type": "text",
"text": "Y"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Other",
}
},
{
"type": "text",
"text": "="
},
{
"type": "text",
"text": "T"
},
{
"type": "text",
"text": "O"
},
]
The objects are in order, so depending on the 'type' of each item AND the order, then I need to combine them like so:
arrayOfObj = [
{
"type": "text",
"text": "= SO"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
}
{
"type": "text",
"text": "HEY"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Other",
}
},
{
"type": "text",
"text": "=TO"
},
]
In summary, whenever 'type' = 'text' then combine every single object with type 'text' that are together. If the next object has type 'notText', then leave it alone until the next item with 'type' = 'text'. Then combine those.
I've asked a previous question that was similar to this with the working answer
let arrayOfObj = [{
"type": "text",
"text": "="
},
{
"type": "text",
"text": " "
},
{
"type": "text",
"text": "S"
},
{
"type": "text",
"text": "O"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
},
{
"type": "text",
"text": "H"
},
{
"type": "text",
"text": "E"
},
{
"type": "text",
"text": "Y"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Other",
}
},
{
"type": "text",
"text": "="
},
{
"type": "text",
"text": "T"
},
{
"type": "text",
"text": "O"
},
];
let newThing = arrayOfObj.reduce(
(textKey, typeKey) => {
if (typeKey.type === "text") {
textKey[0].text += typeKey.text;
} else {
textKey.push({
type: typeKey.type,
attrs: typeKey.attrs
});
}
return textKey;
}, [{
type: "text",
text: ""
}]
);
console.log(newThing);
However it combines all instances where 'type' = 'text' regardless or order or other objects with 'type' = 'notText'.
Would anyone have any idea of how to accomplish this?
I'd suggest using Array.reduce again, starting with an empty array.
If the last item in the array we build up is of type 'text', append the current item, otherwise just add it to the array:
const arrayOfObj = [ { "type": "text", "text": "=" }, { "type": "text", "text": " " }, { "type": "text", "text": "S" }, { "type": "text", "text": "O" }, { "type": "notText", "attrs": { "id": 20, "data": "Something", } }, { "type": "text", "text": "H" }, { "type": "text", "text": "E" }, { "type": "text", "text": "Y" }, { "type": "notText", "attrs": { "id": 20, "data": "Other", } }, { "type": "text", "text": "=" }, { "type": "text", "text": "T" }, { "type": "text", "text": "O" }, ]
const result = arrayOfObj.reduce((acc, curr) => {
// If the last item was of type 'text' _and_ the current item is too.. append the text
if (acc[acc.length-1]?.type === 'text' && curr.type === 'text') {
acc[acc.length-1].text += curr.text;
} else {
// Either current or last item in array was not type 'text'
acc.push(curr)
}
return acc;
}, []);
console.log('Result:', result);
This is how you can do that:
arrayOfObj = [
{
"type": "text",
"text": "="
},
{
"type": "text",
"text": " "
},
{
"type": "text",
"text": "S"
},
{
"type": "text",
"text": "O"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Something",
}
},
{
"type": "text",
"text": "H"
},
{
"type": "text",
"text": "E"
},
{
"type": "text",
"text": "Y"
},
{
"type": "notText",
"attrs": {
"id": 20,
"data": "Other",
}
},
{
"type": "text",
"text": "="
},
{
"type": "text",
"text": "T"
},
{
"type": "text",
"text": "O"
},
]
let output = [];
arrayOfObj.forEach(x => {
if (
x.type == 'notText' ||
output.length == 0 ||
output[output.length - 1].type == 'notText'
) {
output.push(x)
} else {
output[output.length - 1].text += x.text
}
})
console.log(output);
You can use reduce here
const arrayOfObj = [
{ type: "text", text: "=" },
{ type: "text", text: " " },
{ type: "text", text: "S" },
{ type: "text", text: "O" },
{
type: "notText",
attrs: { id: 20, data: "Something" },
},
{ type: "text", text: "H" },
{ type: "text", text: "E" },
{ type: "text", text: "Y" },
{
type: "notText",
attrs: { id: 20, data: "Other" },
},
{ type: "text", text: "=" },
{ type: "text", text: "T" },
{ type: "text", text: "O" },
];
const result = arrayOfObj.reduce((acc, curr) => {
const { type, ...props } = curr;
const last = acc[acc.length - 1];
if (!last || last.type !== "text" || last.type !== type) acc.push(curr);
else last.text = last.text + props.text;
return acc;
}, []);
console.log(result);
I have a time calculation tool which you can find in the following fiddle link. Once someone has selected a platform, task type, component and number of units, the number of units entered should be multiplied with selected component value and show it on the below table. I have managed to get the all populated values but can't do the math. I have tried several attempts but it wasn't working.
var myJson = {
"platforms": [
{
"name": "Sitecore",
"id": "sitecore",
"tasktype": [
{
"name": "Promobox",
"id": "promobox",
"components": [
{
"name": "Accordion",
"id": "accordion",
"time": "20"
},
{
"name": "Box 1",
"id": "box1",
"time": "30"
}
]
},
{
"name": "Video",
"id": "video",
"components": [
{
"name": "Box 2",
"id": "box2",
"time": "25"
},
{
"name": "Box 3",
"id": "box3",
"time": "30"
}
]
}
]
},
{
"name": "Siab",
"id": "siab",
"tasktype": [
{
"name": "Newswire",
"id": "newswire",
"components": [
{
"name": "Box 4",
"id": "box5",
"time": "50"
},
{
"name": "Box 5",
"id": "box5",
"time": "40"
}
]
},
{
"name": "Task Type New",
"id": "tasktypenew",
"components": [
{
"name": "Box 6",
"id": "box6",
"time": "20"
},
{
"name": "Box 7",
"id": "box7",
"time": "100"
}
]
}
]
}
]
};
$.each(myJson.platforms, function (index, value) {
var platform_id;
var tasktype_id;
var component_id;
$("#platform").append('<option rel="' + index + '" value="' + value.id + '">' + value.name + '</option>');
$("#platform").change(function () {
$("#tasktype, #component").find("option:gt(0)").remove();
$("#tasktype").find("option:first").text("Loading...");
platform_id = $(this).find('option:selected').attr('rel');
$.each(myJson.platforms[platform_id].tasktype, function (index1, value1) {
$("#tasktype").find("option:first").text("Select Task Type");
$("#tasktype").append('<option rel="' + index1 + '" value="' + value1.id + '">' + value1.name + '</option>');
});
});
$("#tasktype").change(function () {
$("#component").find("option:gt(0)").remove();
$("#component").find("option:first").text("Loading...");
tasktype_id = $(this).find('option:selected').attr('rel');
$.each(myJson.platforms[platform_id].tasktype[tasktype_id].components, function (index2, value2) {
$("#component").find("option:first").text("Select Component");
$("#component").append('<option rel="' + index2 + '" value="' + value2.time + '">' + value2.name + '</option>');
});
});
});
$(document).ready(function () {
$('#calculate').click(function () {
$('#calc input, #calc select').each(
function (index) {
var input = $(this);
$('#data tbody').append('<tr><td>' + input.val() + '</td></tr>');
});
});
});
JS Fiddle
Ok this took a lot of debugging. You were building your table wrong and not storing data properly. The whole fishing for data was problematic. Here is the debugged calculator:
$(document).ready(function () {
$('#calculate').click(function () {
let tr = $("<tr/>").appendTo("#data tbody");
console.log(tr);
$('#calc input, #calc select').each( function (index) {
console.log($(this));
var input = $(this);
$(tr).append('<td class=row-'+ $(input).attr("id") + '>' + input.val() + '</td>');
});
const componentFactor = $(tr).children(".row-component").text();
const units = $(tr).children(".row-units").text();
const total = componentFactor*units;
$(tr).append('<td>' + total + '</td>');
});
});
notice:
Change of table structure format.
Now appending td's to single tr each time in order to sustain table-row consistency.
Fishing data from row with the help of adding class tag identifier to each td
Showing result.
update fiddle link:
https://jsfiddle.net/x4rLuf88/1/
This is my HTML for server side data to load the data into the table of the data get data from controller
<script type="text/template" id="tablescript">
<td><%=Name%></td>
<td><%=PhoneNumber%></td>
<td><%=CNIC%></td>
<td><%=So%></td>
<td><%=Thumb%></td>
<td><%=Image%></td>
<td><%=NomineeImage%></td>
<td>
<i class="fa fa-pencil-square-o" aria-hidden="true" onclick="editMember('<%= Id%>')" style="cursor:pointer;font-size: 20px;"></i>
<span class="fa fa-trash" aria-hidden="true" style="cursor:pointer;color:red;font-size: 20px;" onclick="deleteMember('<%= Id%>')"></span>
<span class="fa fa-ban" aria-hidden="true" style="cursor:pointer;color:red;font-size: 20px;" onclick="blockMember('<%= Id%>')"></span>
<span class="fa fa-check" aria-hidden="true" style="cursor:pointer;color:green;font-size: 20px;" onclick="activeMember('<%= Id%>')"></span>
</td>
</script>
<table class="table table-hover table-bordered table-striped" id="tblloaddata"></table>
Ajax Request go to the mvc controller and get the list was load to model but not show my datatable.
var table;
var loadtable = function () {
var getUrl = $("#hidLoadMembersUrl").val();
var tmpl = _.template($("#tablescript").html());
table = $("#tblloaddata").DataTable({
"processing": true,
"serverSide": true,
"ajax": {
url: getUrl,
type: "POST"
},
"columns": [
{ "data": "Name", "title": "Name" },
{ "data": "PhoneNumber", "title": "PhoneNumber" },
{ "data": "CNIC", "title": "CNIC" },
{ "data": "So", "title": "SoDoWoName" },
{ "data": "Thumb", "title": "Thumb" },
{ "data": "Image", "title": "Image" },
{ "data": "NomineeImage", "title": "NomineeImage" },
{ "data": null, "title": "Action", "orderable": "false" },
],
"rowCallback": function (row, data) {
console.log(data);
$(row).html(tmpl(data));
}
});
};
You should use render property to display images;
table = $("#tblloaddata").DataTable({
"processing": true,
"serverSide": true,
"ajax": {
url: getUrl,
type: "POST"
},
"columns": [
{ "data": "Name", "title": "Name" },
{ "data": "PhoneNumber", "title": "PhoneNumber" },
{ "data": "CNIC", "title": "CNIC" },
{ "data": "So", "title": "SoDoWoName" },
{ "data": "Thumb", "title": "Thumb" },
{ "data": "Image", "title": "Image", render : function (data, type, full, meta)
{ return '<img src="'+data.Image+'"/>'; }
},
{ "data": "NomineeImage", "title": "NomineeImage" },
{ "data": null, "title": "Action", "orderable": "false" },
],
"rowCallback": function (row, data) {
console.log(data);
$(row).html(tmpl(data));
}
});
I have a datatable with json ajax.
But, i need to pass for the same column two targets. How i do that?
"columns": [
{ "data": "tpPedido" },
{ "data": "os" },
{ "data": "userMobile.nome" },
{ "data": "produto.nmProduto" },
{ "data": "status.NmStatus" },
{ "data": "produto.garantia.descricao" },
{ "data": "valor" },
{ "data": "valoradiantado" },
{ "data": "idPedidoAssistencia" },
{ "data": "idPedidoAssistencia" }
],
And the columndefs i trying to do this:
{ "render": function ( data, type, row ) {
return '<a onclick="relatorioAcerto('+data+')">R$: ' + parseFloat(data).toFixed(2).replace('.', ',').replace(/(\d)(?=(\d{3})+\,)/g, "$1." + '</a>');
}, "targets": 6,9},
You can define directly in columns array. render function accept three parameters. The last parameter holds entire data object.
"columns": [
{ "data": "tpPedido" },
{ "data": "os" },
{ "data": "userMobile.nome" },
{ "data": "produto.nmProduto" },
{ "data": "status.NmStatus" },
{ "data": "produto.garantia.descricao" },
{
"data": null,
"render" : function (data, type, row) {
return '<a href="'+row.idPedidoAssistencia+'" >Click here</a>';
}
},
{ "data": "valoradiantado" },
{ "data": "idPedidoAssistencia" },
{
"data": null,
"render" : function (data, type, row) {
return '<a href="'+row.idPedidoAssistencia+'" >Click here</a>';
}
}
],
Hi I am using a Sharepoint List which I am displaying using DataTables , I referred one the articles and i was to do grouping but i am not able to get Group Totals ,RowGrouping and Subtotal on Datatable
In This field on which I am grouping on is a calculated field called Heirarch for example field values are generaly like Capital.Establishment it is concatenation of two fields
Below is my Code
<script type="text/javascript" charset="utf8" src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<!-- DataTables CSS -->
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/r/dt/dt-1.10.9/datatables.min.css"/>
<!-- DataTables -->
<script type="text/javascript" src="https://cdn.datatables.net/r/dt/dt-1.10.9/datatables.min.js"></script>
<script type="text/javascript" src="http://jquery-datatables-row-grouping.googlecode.com/svn/trunk/media/js/jquery.dataTables.rowGrouping.js"></script>
<style type="text/css">
tr.group, tr.group:hover {
background-color: #ddd !important;
}
.pocell {
font-weight:bold;
}
</style>
<table id="example" class="display" cellspacing="0" width="100%">
<thead>
<tr>
</tr>
</thead>
</table>
<script type="text/javascript">
$(document).ready(function() {
var call = $.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/Web/Lists/GetByTitle('Demo%20Custom%20List')/items?$select=Hierarch,Title,Year2015,Year2016,Year2017,Year2018,Year2019,Exp_x0020_Total",
type: "GET",
dataType: "json",
headers: {
Accept: "application/json;odata=verbose"
}
});
call.done(function (data,textStatus, jqXHR){
var marker;
var table = $('#example').DataTable({
"aaData": data.d.results,
"columns": [
{
"title": "Hierarchy",
"mData": "Hierarch",
"visible": false
}, {
"title": "Title",
"mData": "Title"
}, {
"title": "Year2015",
"mData": "Year2015",
"sortable": false
}, {
"title": "Year2016",
"mData": "Year2016",
"sortable": false
}, {
"title": "Year2017",
"mData": "Year2017",
"sortable": false
}, {
"title": "Year2018",
"mData": "Year2018",
"sortable": false
}, {
"title": "Year2019",
"mData": "Year2019",
"sortable": false
}, {
"title": "Total Expense",
"mData": "Exp_x0020_Total",
"sortable": false
}
],
"drawCallback": function (settings) {
var api = this.api();
var rows = api.rows({
page: 'current'
}).nodes();
var last = null;
api.column(0, {
page: 'current'
}).data().each(function (group, i) {
if (last !== group) {
$(rows).eq(i).before(
$("<tr></tr>", {
"class": "group",
"data-id": group
}).append($("<td></td>", {
"colspan": 1,
"class": "pocell",
"text": "Hierarch # " + group.split('_').join('.')
})).append($("<td></td>", {
"id": "e" + group,
"class": "noCount",
"text": "60.00"
})).append($("<td></td>", {
"id": "f" + group,
"class": "noCount",
"text": "60.00"
})).append($("<td></td>", {
"id": "g" + group,
"class": "noCount",
"text": "50.00"
})).append($("<td></td>", {
"id": "h" + group,
"class": "noCount",
"text": "40.00"
})).append($("<td></td>", {
"id": "i" + group,
"class": "noCount",
"text": "30.00"
})).append($("<td></td>", {
"id": "j" + group,
"class": "noCount",
"text": "20.00"
})).prop('outerHTML'));
last = group;
}
val = api.row(api.row($(rows).eq(i)).index()).data();
$("#e" + val.Hierarch.split('.').join('_')).text(parseFloat($("#e" + val.Hierarch.split('.').join('_')).text()) + parseFloat(val.Year2015));
// $("#e" + val.Hierarch).text(parseFloat($("#e" + val.Hierarch).text()) + val.Year2015);
$("#f" + val.Hierarch).text(parseFloat($("#f" + val.Hierarch).text()) + val.Year2015);
$("#g" + val.Hierarch).text(parseFloat($("#g" + val.Hierarch).text()) + val.Year2015);
$("#h" + val.Hierarch).text(parseFloat($("#h" + val.Hierarch).text()) + val.Year2015);
$("#i" + val.Hierarch).text(parseFloat($("#i" + val.Hierarch).text()) + val.Year2015);
$("#j" + val.Hierarch).text(parseFloat($("#j" + val.Hierarch).text()) + val.Year2015);
});
}
});
});
call.fail(function (jqXHR,textStatus,errorThrown){
alert("Error retrieving Tasks: " + jqXHR.responseText);
});
} );
</script>