Kendo grid columns with dynamic data - javascript

Need help with Kendo Grid, where in I have dynamic columns on Kendo Grid.
dynamicCols- Object is a object which has list of title and value properties which could be dynamic where it could have any number of objects in the list with title, value pair.
Kendo grid works well if JSON has a flat structure which has all properties at same level and I haven't come across this kind of hierarchial/JSON structure until now.
This grid also needs to support server side sorting and filtering with C# Web API, with Kendo Datasource API for server side sorting and filtering.
Existing kendo column mapping
var cols = [
{ field: 'name', title: 'Name', encoded: false },
{ field: 'id', title: 'Id' },
{ field: 'age', title: 'Age }
]
json = [{
name:'XYZ', id:123, age:45,
dynamicCols: [{title:'Gender',value:'Male'},
{title:'Veteran',value:'Yes'}]
}, {
name:'Jim', id:555, age:24,
dynamicCols: [{title:'Gender',value:'Male'},
{title:'Veteran',value:'No'}]
}, {
name:'Nick', id:557, age:78,
dynamicCols: [{title:'Gender',value:'Female'},
{title:'Veteran',value:'No'}]
}]
**Expected Grid**
Name Id Age Gender Veteran
XYZ 123 45 Male Yes
Jim 555 24 Male No
For Json2
json2 = [
{name:'XYZ', id:123, age:45,
dynamicCols: [{title:'SSN',value:'xx-xx-7891'}]
},
{name:'Jim', id:555, age:24,
dynamicCols: [{title:'SSN',value:'xx-xx-7892'}]
},
{name:'Nick', id:557, age:78,
dynamicCols: [{title:'SSN',value:'xx-xx-7895'}]
}];
**Expected Grid**
Name Id Age Gender SSN
XYZ 123 45 Male xx-xx-7891
Jim 555 24 Male xx-xx-7892

You have two options:
When you are done fetching the data and before creating the new Grid, resolve the JSON object and create flat columns object that the Grid accepts
Your second option is to forget the idea of creating dynamic columns and instead have a template column that dynamically resolves what it needs to display. In such cases you create an external function that you can call from your template. This way you do not end up with complicated and crappy templates. How to invoke external function from a template is covered here.

The easiest solution for me has been to make all columns and then end it by hiding those columns I did not need.
Even hiding around 50 columns did not take any noticable time.
(I had the luxury of knowing all potential columns that could appear)

Related

How to format a list of string into columns of react bootstrap table 2 such that data doesn't flows out of actual columns

I am trying to render some data in tabular form using react-bootstrap-table but the data of one column is overlapping with the data of other columns. i wanted to keep my layout fixed and thus have added the css layout:fixed which is actually a requirement as well. But the final result is:
Actually for this column i'm getting an array of string from backend. e.g. ["DEPT","OLD","CUSTOM_FUNCTION",...] which is getting converted into a single string internally by react and i'm not sure how to further format it.
I also searched in react table docs at : https://react-bootstrap-table.github.io/react-bootstrap-table2/docs/basic-celledit.html#rich-editors but didn't find anything.
My ultimate goal is to visualize the data in a much better way like drop down or each element of array in new line within the same column expandable on some mouse click.
The above image can be considered as sample requirement where only the first element of list will be displayed on load and after clicking on arrow button it will show all the list items below one another in the same column as shown below.
I am not able to figure out which column prop will help me or whether it's even possible or not. The goal is exactly the same but a simple new line separated data will also do.
Column Definition Code:
{
dataField: 'data',
text: 'DATA',
editable: false,
filter: textFilter(),
headerStyle: () =>
{
return { width: '100px', textAlign: 'center'};
}
}
Table Creation Code:
<BootstrapTable
keyField='serialNo'
data={ this.state.data }
columns={ this.state.columns }
filter={ filterFactory() }
pagination={ paginationFactory({sizePerPage: 4}) }
cellEdit={ cellEditFactory({ mode: 'click'}) }
striped
hover
/>
Kindly help or suggest something appropriate.
Thanks
Check this sandbox.
https://codesandbox.io/s/competent-rain-2enlp
const columns = [{
dataField: 'id',
text: 'Product ID',
}, {
dataField: 'name',
text: 'Product Name'
}, {
dataField: 'labels',
text: 'Labels',
formatter: (cell) => {
return <>{cell.map(label => <li>{label}</li>)}</>
},
}];
You need to define your own formatter in order to include "complex" html inside your table cell.

Change data before it is displayed, on click of dropdownlist in kendo grid

Is there a way to change the data before it is displayed in a dropdown AS you click to edit the field?
Using a simpler solution and trying to use dataBinding, which is supposed to fire before the data is bound (and available on dropDownList as well), it doesn't appear to be able to change the data before the data runs. Or at least doesn't update it.
The deep dive into the problem is that I want to run a for loop around the array of data, and perform some operations on it, based on the rest of the data in the row.
The simpler idea, is that I want to edit the data before it is displayed, on click of the kendo grid.
https://dojo.telerik.com/UROwaWoN
var mydata = [
{ name: "Jane Doe", age: 30 },
{ name: "John Doe", age: 33 }];
$("#grid").kendoGrid({
columns: [
{ field: "name" },
{ field: "age" }
],
dataSource: mydata,
dataBinding: function(e) {
mydata.push({ name: "Kane Madison", age: 24 });
console.log("dataBinding");
}
});
The answer was that I have to set the datasource again. I did this by setting the datasource within the "edit" function on the options (before the dropdownlist select event). It looks like this:
edit: function(event) {
// .....
if (selectedFieldName == "thefieldIwant") {
let newDataSource = remapDataBased
let dropdownList = ..... (get dropdownlist from Kendogrid)
dropdownList.setDataSource(newDataSource);
}
}
I think it's possible there are other solutions to this, but this has been up a few days and nobody has found them yet.

kendo ui stacked bar chart datasource grouped not in order

I've created a Stacked bar chart with Kendo ui, here: http://jsfiddle.net/Came19xx/t06zq2nr/4/
my problem is that chart put values not in order.
In my Datasource, i have an "open" and a "suspended" value, like that:
var data2 = [{"name":"abc","num":1,"state":"open"},
{"name":"abc","num":1,"state":"suspended"},
{"name":"def","num":2,"state":"open"},
{"name":"def","num":5,"state":"suspended"},
{"name":"ghi","num":3,"state":"open"},
{"name":"ghi","num":21,"state":"suspended"},
{"name":"jkl","num":4,"state":"open"},
{"name":"jkl","num":9,"state":"suspended"},
{"name":"mno","num":5,"state":"open"},
{"name":"mno","num":5,"state":"suspended"},
{"name":"pqr","num":6,"state":"open"},
{"name":"pqr","num":14,"state":"suspended"},
{"name":"stu","num":7,"state":"open"},
{"name":"stu","num":6,"state":"suspended"},
{"name":"vwxyz","num":8,"state":"open"},
{"name":"vwxyz","num":5,"state":"suspended"}];
So i grouped by state the datasource, but i don't get the open value corresponding to the name on the barchart and i can't sort it by name cause it will stop working.
For example, i want that abc is in the first line, with 1 in the left side (orange) of the stacked bar and 2 on the right side (red), instead i got vwxyz with the correct suspended value (5) and the wrong open value (3 instead of 8)
the "name" field and the "num" field may can change their value.
Try adding name as a sort field on the datasource:
dataSource: {
data: data2,
group: [{
field: "state",
dir: "desc"
}],
sort: {
field: "name",
dir: "asc"
}
}
Updated FIDDLE

Typeahead templating, if/else

thanks for the help on this question: Typeahead result formatting, this is a follow up.
My JSON looks like
[{ name="Long Island", type="2", id="1234"}, { name="New York", type="1", id="5678"}]
In the drop down list I need to be able to seperate type 1 from type 2, so
Type 1 heading
type 1 item
type 1 item*
Type 2 heading
type 2 item
type 2 item
If there are no results for type 1, then don't show the heading. Same for type 2.
Is this possible with typeahead and a templating engine? I'm using Hogan but I'm not fussy.
The "Typeahead" way of doing this is to separate your dataset into 2 datasets, one that will only return "type 1" items and another that will return only "type 2" items. In typeahead, each dataset can have its own header, which will behave exactly the way you want it.
$autocomplete.typeahead([{
name: 'location 1',
remote: {
url: 'http://pathtomysite.com/%QUERY?type=1',
dataType: 'jsonp',
valueKey: 'name'
filter: function (parsedResponse) { return parsedResponse.locations; }
},
template: [
'<p class="repo-name">{{name}}</p>',
'<p class="repo-description">{{id}}</p>'
].join(''),
header: '<b>Type 1</b>'
engine: Hogan
}, {
name: 'location 2',
remote: {
url: 'http://pathtomysite.com/%QUERY??type=2',
dataType: 'jsonp',
valueKey: 'name'
filter: function (parsedResponse) { return parsedResponse.locations; }
},
template: [
'<p class="repo-name">{{name}}</p>',
'<p class="repo-description">{{id}}</p>'
].join(''),
header: '<b>Type 2</b>'
engine: Hogan
}])
Given that you don't have control over the JSON part, you have 2 options:
Option 1
Use 2 datasets, with the same query. In one of them, the filter will only return "type 1" entries, in the other the filter will only return "type 2" answers.
That's twice the calls to the JSON, so twice the load on your server. The client side will not see a delay, though, as the queries are concurrent.
That's a hackish solution, but OTOH it's clean (client-side-wise), and requires very little code.
Option 2
Use only 1 dataset, and so some work in your filter. Basically, return an array with an entry for the "type 1" header, then all the type 1 entries, then an entry for the "type 2" header, then all the type 2 entries.
The array is an array of objects. Each object will also have a class member. In the entries for the "type 1" and "type 2" headers set the class to "header" or something along the lines, and:
1) Have your template include the class.
2) Have your CSS make the class unselectable, unclickable, and styled the way you want it.
I like option #1 better.

Dynamic Models, Stores, and Views -- Best way to

NOTE: Author is new to EXT JS and is trying to use MVC in his projects
imagine i have a web service whose data model is not fixed. I would want to have my models dynamically created, from which i dynamically create stores and hence dynamic components whose data is in those stores.
Lets start by seeing a sample class definition of a model:
Ext.define('MNESIA.model.User', {
extend: 'Ext.data.Model'
});
In this model definition, i have left out the 'fields' parameter in the config object. This is because whwnever i create an instance of a model of the type above, i want to dynamically give it its fields definition, in other words i can have many instances of this model yet all having different definition of their 'fields' parameter.
From here i create a definition of the store, like this:
Ext.define('MNESIA.store.Users', {
extend: 'Ext.data.Store',
autoLoad: true
}
});
There, i have a store definition. I have left out the 'model' parameter because i will attach it to every instance of this class dynamically. Infact, even the 'data' and 'proxy' settings are not mentioned as i would want to asign them during the instantiation of this store.
From there, i would want to have dynamic views, driven by dynamic stores. Here below i have a definition of a Grid
Ext.define('MNESIA.view.Grid' , {
extend: 'Ext.grid.Panel',
alias : 'widget.mygrid',
width: 700,
height: 500
});
I have left out the following parameters in the Grid specification: 'columns', 'store' and 'title' . This is because i intend to have many Grids created as instances of the specification above yet having dynamic stores, titles and column definitions.
Some where in my controller, i have some code that appears like this:
function() {
var SomeBigConfig = connect2Server();
/*
where:
SomeBigConfig = [
{"model":[
{"fields":
["SurName","FirstName","OtherName"]
}
]
},
{"store":[
{"data":
{"items":[
{"SurName":"Muzaaya","FirstName":"Joshua","OtherName":"Nsubuga"},
{"SurName":"Zziwa","FirstName":"Shamusudeen","OtherName":"Haji"},
...
]
}
},
{"proxy": {
"type": "memory",
"reader": {
"type": "json",
"root": "items"
}
}
}
]
},
{"grid",[
{"title":"Some Dynamic Title From Web Service"},
{"columns": [{
"header": "SurName",
"dataIndex": "SurName",
"flex": 1
},{
"header": "FirstName",
"dataIndex": "FirstName",
"flex": 1
},
{
"header": "OtherName",
"dataIndex": "OtherName",
"flex": 1
}
]}
]
}
]
*/
var TheModel = Ext.create('MNESIA.model.User',{
fields: SomeBigConfig[0].model[0].fields
});
var TheStore = Ext.create('MNESIA.store.Users',{
storeId: 'users',
model: TheModel,
data: SomeBigConfig[1].store[0].data,
proxy: SomeBigConfig[1].store[1].proxy
});
var grid = Ext.create('MNESIA.view.Grid',{
store: TheStore,
title: SomeBigConfig[2].grid[0].title,
columns: SomeBigConfig[2].grid[1].columns
});
// From here i draw the grid anywhere on the, page say by
grid.renderTo = Ext.getBody();
// end function
}
Now this kind of dynamic creating of models, then stores, and then grids does result into memory wastage and so this would require the destroy methods of each component to be called each time we want to destroy that component.
Questions:
Qn 1: Does the MVC implementation of EXT JS 4 permit this ?
Qn 2: How would i gain the same functionality by using the xtypes of my new classes. Say for example:
{
xtype: 'mygrid',
store: TheStore,
title: SomeBigConfig[2].grid[0].title,
columns: SomeBigConfig[2].grid[1].columns
}
Qn 3: If what i have written above really works and is pragmatically correct, can i apply this to all components like Panels, TabPanels, Trees (whereby their Configs are sent by a remote server) ?
Qn 4: If i have Controllers A and B, with controller A having a specification of views: [C, D] and Controller B having views: [E, F], would it be correct if actions generated by view: E are handled by Controller A ? i.e. Can a controller handle actions of a view which is not registered in its views config ?
NOTE: am quite new to Ext JS but would love to learn more. Advise me on how to improve my EXT JS learning curve. Thanks
In my option ,your model must map onto the store that is to be rendered to the view like for example,if implement the model part like this
{"model":[{"fields":[{name:'name',type:'string'},
{name:'id',type:'string'}]}]} ,this will be easily mapped onto the store for the view render it.

Categories

Resources