Cascading dropdowns in DataTables - javascript

I have defined my datatables editor as follows :
editor = new $.fn.dataTable.Editor({
ajax: "./DataServlet",
table: "#example",
legacyAjax: true,
idSrc: "rowID",
fields: [{
label: "Data Id",
name: "dataId",
type: "readonly"
},{
label: "Name",
name: "name",
type: "readonly"
},{
label: "Field L1",
name: "fieldL1",
type: "selectize",
options: getFieldL1()
},{
label: "Field L2",
name: "fieldL2",
type: "selectize",
options: getFieldL2()
},{
label: "Field L3",
name: "fieldL3",
type: "selectize",
options: getFieldL3()
},{
label: "User Name",
name: "userName",
type: "readonly"
}],
});
The fieldL3 value is dependent on fieldL2 which is dependent on fieldL1.
The dependency is as shown in the table below :
So, initially the fieldL1 dropdown values would be [A,B,C] and if value I select is 'A', then fieldL2 dropdown values should only be [Q,W,R] and if I select 'Q' for fieldL2, the fieldL3 dropdown should only have [T,U].
So, far I have tried the following :
$("#DTE_Field_fieldL1").on('change', function(data) {
let c1_value = data.currentTarget.value;
let c2_opts = $(".DTE_Field_Name_fieldL2 .selectize-dropdown-content")[0].children;
let valid_c2_opts = Object.keys(json[c1_value]);
for(let i = 0; i < c2_opts.length; i++) {
if(valid_c2_opts.includes(c2_opts[i].dataset.value))
{
c2_opts[i].className = "option";
}
else {
c2_opts[i].className = "option d-none";
}
}
editor.enable('fieldL2');
});
$("#DTE_Field_fieldL2").on('change', function(data) {
let c1_value = $("#DTE_Field_fieldL1")[0].value;
let c2_value = data.currentTarget.value;
let c3_opts = $(".DTE_Field_Name_fieldL3 .selectize-dropdown-content")[0].children;
let valid_c3_opts = Object.values(json[c1_value][c2_value]);
for(let i = 0; i < c3_opts.length; i++) {
if(valid_c3_opts.includes(c3_opts[i].dataset.value ))
{
c3_opts[i].className = "option";
}
else {
c3_opts[i].className = "option d-none";
}
}
editor.enable('fieldL3');
});
So, the json has the data separated in JSON format and I am trying to hide/show the values based on what is selected.
The issue I am facing with the above approach is whenever I try to change a value, the onChange function doesn't get called.
How do I achieve it in the datatables editor?

Related

ExtJS Add filtering in Grid for hasMany association

I have a data model that I want to be able to add a generic amount of filters to. I am specifying a name and a value. How can I add these hasMany associated fields as filters to my grid? I have attempted to write custom filtering option, but I can't have filters show up without an attached dataIndex, which is not available for the hasMany association.
Ext.define('AirGon.model.Project', {
extend: 'Ext.data.Model',
fields: [
{ name: 'Link', type: 'string' },
{ name: 'Title', type: 'string' },
{ name: 'Description', type: 'string' },
{ name: 'MappedMetadata', mapping: 'Metadata'},
{ name: 'XMax', type: 'float' },
{ name: 'XMin', type: 'float' },
{ name: 'YMax', type: 'float' },
{ name: 'YMin', type: 'float' }
],
hasMany: { model: 'Metadata', name: 'Metadata', associationKey: 'Metadata' }
});
Ext.define('Metadata', {
extend: 'Ext.data.Model',
fields: ['Name', 'Value']
});
This is my custom filtering attempt. I am getting the DataStore from the main store and then adding custom rendering, but I can't filter or sort this column because of the lack of a dataIndex.
var column = {
header: 'Meta',
//?????????dataIndex: 'MappedMetadata[0]',?????
sortable: true,
filterable: true,
filter: {
type: 'string'
},
renderer: function (value, meta, record) {
console.log(record.MetadataStore.data.items[index].data)
return record.MetadataStore.data.items[index].data.Value;
}
}
Data. The data is modeled so that a variable amount of metadata can be entered and the 'tag' will not be known by the system.
{
"Link": "link.com",
"Title": "project",
"Description": "descript",
"State": "",
"Metadata": [
{
"Name": "County",
"Value": "32"
},
{
"Name": "Info",
"Value": "info"
},
{
"Name": "State",
"Value": "TN"
}
],
"XMin": "-1",
"XMax": "-1",
"YMin": "1",
"YMax": "1"
}
I was able to solve this by dynamically flattening the data model and adding columns once the store has been loaded. Although this breaks the MVC structure this was the best solution I came up with so it might be able to help you.
var defaultColumns = [];
var store = Ext.getStore('store');
store.on('load', function (store) {
var model = store.model;
var fields = model.getFields();
store.getAt(0).MetadataStore.data.items.forEach(function (item, index) {
var header = item.data.Name;
//isField returns a boolean if the field is already part of the data model
if (!isField(fields, header)) {
//Add a new metadata field to the data model
var field = { name: header, mapping: 'Metadata[' + index + '].Value' }
fields.push(field)
//Add a new metadata column
var column = {
header: header,
dataIndex: header,
sortable: true,
filterable: true,
filter: {
type: 'list'
},
flex: 0.2
}
defaultColumns.push(column);
}
});
model.setFields(fields);
//reload the grid after adding columns
var gridView = Ext.ComponentQuery.query('gridpanel')[0];
gridView.reconfigure(store, defaultColumns);
});
//reload the data after creating new fields
store.load();
I then set the columns of the grid to defaultColumns.
{
xtype: 'grid',
store: 'Projects',
overflowX: 'auto',
autoScroll: true,
features: [filters],
columns: defaultColumns
}

KendoUI Grid - Complex JSON with inconsistent keys

I know this is probably been asked before, but having tried to find an answer - I am guessing either I am not comprehending some of the answers right, or I am looking at the problem all wrong.
I am using a complex SLC loopback query - and the api returns the JSON in the following format:
> [ {"id":"1","name":"John", "type":"commercial",
> "address":{"street1":"1 dalhousie lane", "street2":"some street"}},
> {"id":"2","name":"Jane", "type":"commercial",
> "address":{"street1":"15 dalhousie lane", "postcode":"1283833"}},
> {"id":"3","name":"Jack", "address":{"street1":"12 dalhousie lane",
> "postcode":"9383833", "geo":{"lat":"9393939","long":"99393939"}}}
]
As you can see, following are the problems -
1. Nested JSON - multiple levels
2. Inconsistent / Missing Key values,
e.g.: "id":"2" -> "type" -> missing
e.g.: "id":"3" -> "address" -> "geo"
When I try to use the KendoUI grid to display the above json, i get errors such as - property undefined. I understand, options i can explore and what I am supposed to do -
Define the schema - how? Especially for missing keys.
Parse the data ?
Would be great if someone could kindly let me know, how to move forward with this. Below is the code for the grid -
$("#grid").kendoGrid({
dataSource: {
transport: {
read: {
url: apiurl,
dataType: "json",
}
}
},
columns: [
{
field: "id",
title: "User Id"
},
{
field: "name",
title: "User Name",
},
{
field: "type",
title: "User Type",
},
{
field: "address.street1",
title: "Street 1",
},
{
field: "address.street2",
title: "Street 2",
},
{
field: "address.postcode",
title: "Street 2",
},
{
field: "address.geo.lat",
title: "Latitude",
},
{
field: "address.geo.long",
title: "Longitude",
}
]
});
You can use column templates:
columns: [
{
field: "id",
title: "User Id"
},
{
field: "name",
title: "User Name",
},
{
field: "type",
title: "User Type",
template: function(dataItem) {
return dataItem.type ? kendo.htmlEncode(dataItem.type) : "";
}
},
{
field: "address",
title: "Street 1",
template: function(dataItem) {
return dataItem.address.street1 ? kendo.htmlEncode(dataItem.address.street1) : "";
}
},
{
field: "address",
title: "Street 2",
template: function(dataItem) {
return dataItem.address.street2 ? kendo.htmlEncode(dataItem.address.street2) : "";
}
},
{
field: "address",
title: "Post Code",
template: function(dataItem) {
return dataItem.address.postcode ? kendo.htmlEncode(dataItem.address.postcode) : "";
}
},
{
field: "address",
title: "Latitude",
template: function(dataItem) {
return dataItem.address.geo && dataItem.address.geo.lat ? kendo.htmlEncode(dataItem.address.geo.lat) : "";
}
},
{
field: "address",
title: "Longitude",
template: function(dataItem) {
return dataItem.address.geo && dataItem.address.geo.long ? kendo.htmlEncode(dataItem.address.geo.long) : "";
}
}
]
Each template is a function that checks for the existence of the field and then returns the field value or an empty string.
Working DEMO
Another option is the use the schema.parse method to handle adding a default value for the missing field. Here is a link to the documentation - http://docs.telerik.com/kendo-ui/api/javascript/data/datasource#configuration-schema.parse
<script>
var dataSource = new kendo.data.DataSource({
transport: {
read: {
url: "yoururl",
dataType: "jsonp"
}
},
schema: {
parse: function(response) {
var items = [];
for (var i = 0; i < response.length; i++) {
var item = response[i];
if(!item.address.geo){
if(!item.address.geo.lat){
item.address.geo.lat = 0.0;
}
}
items.push(item);
}
return items;
}
}
});
dataSource.fetch(function(){
var data = dataSource.data();
var product = data[0];
console.log(product.name);
});
</script>
Hope this helps.
Wade

Adding items to a Kendo multiSelect

I've got a Kendo Grid and on its DataBound event, I want to add its data source to a Kendo MultiSelect. So, when the data from the grid is loaded, the below function is fired.
Here's what I have tried so far, without success, but from the code you can see what I intend:
function addToMultiSelect() {
var multiSelect = $("#multiSelect").data("kendoMultiSelect");
var grid = $("#grid").data("kendoGrid");
var places = grid.dataSource._data;
for (var i = 0; i < places.length; i++) {
var row = instPlaces[i];
var id = row.Id;
var mediumDescription = row.MediumDescription;
alert(id + " - " + mediumDescription);
multiSelect.dataSource.insert(i, { text: mediumDescription, value: id })
}
multiSelect.dataSource.read();
}
The alert properly shows the id and description of all the datagrid's items, so, I'm getting the data from the grid right.
I add them to the multiSelect's datasource, the last line is to refresh it and show the new data, but it doesn't. The multiSelect remains empty.
Try the following:
function addToMultiSelect() {
var multiSelect = $("#multiSelect").data("kendoMultiSelect");
var grid = $("#grid").data("kendoGrid");
var places = grid.dataSource.data();
// Read original data content
var multiData = multiSelect.dataSource.data();
for (var i = 0; i < places.length; i++) {
...
// insert new element into copy of multiselect data
multiData.push({ text: mediumDescription, value: id })
}
// Write back the modified data
multiSelect.dataSource.data(multiData);
}
See the following code example:
$(document).ready(function() {
function addToMultiSelect(e) {
var grid = this;
var data = this.dataSource.data();
var multiData = [];
for (var i = 0; i < data.length; i++) {
multiData.push({ text: data[i].ShipName, value: i });
}
multi.dataSource.data(multiData);
}
var multi = $("#multi").kendoMultiSelect({
dataSource: {
data: [
{ text: "ship 1", value: 1 },
{ text: "ship 2", value: 2 },
{ text: "ship 3", value: 3 },
{ text: "ship 4", value: 4 }
]
},
dataTextField: "text",
dataValueField: "value"
}).data("kendoMultiSelect");
$("#grid").kendoGrid({
dataSource: {
type: "odata",
transport: {
read: "http://demos.telerik.com/kendo-ui/service/Northwind.svc/Orders"
},
schema: {
model: {
fields: {
OrderID: { type: "number" },
Freight: { type: "number" },
ShipName: { type: "string" },
OrderDate: { type: "date" },
ShipCity: { type: "string" }
}
}
},
pageSize: 20,
serverPaging: true,
serverFiltering: true,
serverSorting: true
},
dataBound: addToMultiSelect,
height: 550,
columns: [
"OrderID",
"Freight",
{
field: "OrderDate",
title: "Order Date",
format: "{0:MM/dd/yyyy}"
},
{
field: "ShipName",
title: "Ship Name"
},
{
field: "ShipCity",
title: "Ship City"
}
]
});
});
html { font-size: 12px; font-family: Arial, Helvetica, sans-serif; }
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1316/styles/kendo.common.min.css" />
<link rel="stylesheet" href="http://cdn.kendostatic.com/2014.3.1316/styles/kendo.default.min.css" />
<script src="http://cdn.kendostatic.com/2014.3.1316/js/jquery.min.js"></script>
<script src="http://cdn.kendostatic.com/2014.3.1316/js/kendo.all.min.js"></script>
Ship Names copied from Grid DataSource: <input id="multi"/>
Grid
<div id="grid"></div>

Displaying Form details in slickgrid on submit

In my JSP page I have a form with many details to be entered, once the user click the submit then I want to display the results in a grid below the form as an item.
I am fetching each details using JSP Scriptlet and assigning it to slickgrid, here is the code for doing that
<script>
var grid;
dataView = new Slick.Data.DataView();
var columns = [
{id: "SlNo", name: "SlNo", field: "SlNo"},
{id: "ItemName", name: "ItemName", field: "ItemName"},
{id: "PartNo", name: "PartNo", field: "PartNo"},
{id: "BatchNo", name: "BatchNo", field: "BatchNo"},
{id: "UnitRate", name: "UnitRate", field: "UnitRate"},
{id: "Quantity", name: "Quantity", field: "Quantity"},
{id: "Discount", name: "Discount", field: "Discount"},
{id: "NetAmount", name: "NetAmount", field: "NetAmount"},
{id: "TaxRate", name: "TaxRate", field: "TaxRate"},
{id: "TaxAmount", name: "TaxAmount", field: "TaxAmount"},
{id: "TotalAmount", name: "TotalAmount", field: "TotalAmount"}
];
var options = {
enableCellNavigation: true,
enableColumnReorder: false
};
grid = new Slick.Grid("#myGrid", dataView, columns, options);
dataView.onRowCountChanged.subscribe(function (e, args) {
grid.updateRowCount();
grid.render();
});
dataView.onRowsChanged.subscribe(function (e, args) {
grid.invalidateRows(args.rows);
grid.render();
});
$('#btnSubmit').click(function() {
var data = [];
var i=0;
<%ERPConnectionManager erpConn = (ERPConnectionManager) session.getAttribute("erpCon");
ConfirmFunction(request, erpConn);
ArrayList<SalesRecCdty> listSalesRec = (ArrayList<SalesRecCdty>) session.getAttribute("listval");
Iterator itrn = listSalesRec.iterator();
while (itrn.hasNext()) {
SalesRecCdty salesrec = (SalesRecCdty) itrn.next();
String itemName = salesrec.getCommName().toString();
String partNo = "";
String batchNo = salesrec.getBatchNo();
String unitRate = String.valueOf(salesrec.getUnitrate());
String quanity = String.valueOf(salesrec.getReqQty());
String discount = String.valueOf(salesrec.getDiscount());
String netAmount = String.valueOf(salesrec.getNetValue());
String taxRate = String.valueOf(salesrec.getTaxpercent());
String taxAmount = String.valueOf(salesrec.getTaxtotal());
String totAmount = String.valueOf(salesrec.getTotalvalue());
%>
data[i]={
SlNo: i+1,
ItemName:"<%= itemName%>",
PartNo:"<%= partNo%>",
BatchNo:"<%= batchNo%>",
UnitRate:"<%= unitRate%>",
Quantity:"<%= quanity%>",
Discount:"<%= discount%>",
NetAmount:"<%= netAmount%>",
TaxRate:"<%= taxRate%>",
TaxAmount:"<%= taxAmount%>",
TotalAmount:"<%= totAmount%>"
};
i++;
<%
}
%>
// grid = new Slick.Grid("#myGrid", data, columns, options);
dataView.beginUpdate();
dataView.setItems(data);
dataView.endUpdate();
});
e.preventDefault();
var ajaxdata = $('#cbobxOffice').val();
$.ajax({
cache: false,
success: function(data) {
}
});
</script>
I am able to fetch the data to the data array.. but the rows are not displayed in the grid, please help

Filtering jqGrid by multiple conditions at client side

I have a jqGrid with some records and want to filter the records based on multiple conditions.
For instance, if there are three columns, Name, Age and City and I want to filter the grid on the following condition:
Name = "Mark" and Age = 25 and City = 'NY'
the following code works fine-
var grid = jQuery("#memberDetails");
var postdata = grid.jqGrid('getGridParam', 'postData');
var filterArray = new Array();
var filterConidtion;
filterConidtion = new Object();
filterConidtion.field = "name";
filterConidtion.op = "eq";
filterConidtion.data = "Mark";
filterArray.push(filterConidtion);
filterConidtion = new Object();
filterConidtion.field = "Age";
filterConidtion.op = "eq";
filterConidtion.data = "25";
filterArray.push(filterConidtion);
filterConidtion = new Object();
filterConidtion.field = "City";
filterConidtion.op = "eq";
filterConidtion.data = "NY";
filterArray.push(filterConidtion);
jQuery.extend(postdata, {
filters: {
"groupOp": "and",
"rules": filterArray
}
});
grid.jqGrid('setGridParam', {
search: true,
postData: postdata
});
grid.trigger("reloadGrid", [{
page: 1
}]);
but I am not sure how to make the following filter work:
Name = "Mark" and Age = 25 and (City = 'NY' OR City = 'FL')
The groupOp works either on AND or on OR condition, not sure how to embed a sub condition within the groupOp
Thanks.
Format of filters are described in the documentation. To implement more complex searching criteria one can use groups property of filters. The corresponding code could be about the following:
var $grid = $("#memberDetails");
$.extend($grid.jqGrid("getGridParam", "postData"), {
filters: JSON.stringify({
groupOp: "AND",
rules: [
{ field: "Name", op: "eq", data: "Mark" },
{ field: "Age", op: "eq", data: "25" }
],
groups: [
{
groupOp: "OR",
rules: [
{ field: "City", op: "eq", data: "NY" },
{ field: "City", op: "eq", data: "FL" }
],
groups: []
}
]
})
});
$grid.jqGrid("setGridParam", {search: true})
.trigger('reloadGrid', [{current: true, page: 1}]);

Categories