Dynamically add "comment" during validation in Handsontable - handsontable

I can see that there are ways of creating comments in the cells array before rendering, and using the context menu. But is there a way to create a comment after a change?
I originally tried this:
var errors = [];
var hot = new Handsontable(container, {
data: vendors,
startRows: 1,
afterChange: function(changes, source) {
var row = changes[0][0];
var col = changes[0][1];
errors.push({
row: row,
col: col,
comment: "Error"
})
comments: errors
}
But it seems as though changing the errors object doesn't automatically render the comments. Is there a better way?

Comment can be added on meta object as follows
var hot = new Handsontable(container, {
data: vendors,
startRows: 1,
afterChange: function(changes, source) {
var row = changes[0][0];
var col = changes[0][1];
hot.getCellMeta(row, col).comment = 'Error';
}
}

Programmatically, you can try this:
this.instance.getPlugin('comments').setCommentAtCell(row, col, "some text comment");
// or
hot_isstance.setCommentAtCell(row, col, "some text comment");

Related

What's the best way to find specific column in amCharts XYChart?

I need to trigger hover of a specific column and/or segment in an XYChart (amCharts). I've managed to make it work, however it feels like there should be an easier way.
The scenario is that the chart data is also displayed in a table next to the chart. When a row in the table is hovered, I want to set hover of the corresponding column.
The data looks something like this:
const data = [{
x: 'Kalle',
value: 12,
meta: {id: 12432341}
},{
x: 'Nisse',
value: 20,
meta: {id: 54251114}
},{
x: 'Bosse',
value: 8,
meta: {id: 16517346}
}]
And the chart is built like this:
const chart = am4core.create('chartArea', am4charts.XYChart)
// Add category axis
const xAxis = chart.xAxes.push(new am4charts.CategoryAxis())
xAxis.data = categories.map((c) => ({x: c}))
xAxis.dataFields.category = 'x'
// Add value axis
const axis = chart.yAxes.push(new am4charts.ValueAxis())
// Add column series
const series = chart.series.push(new am4charts.ColumnSeries())
series.data = data
series.dataFields.valueY = 'value'
series.dataFields.categoryX = 'x'
series.yAxis = axis
series.bullets.push(new am4charts.CircleBullet())
series.columns.template.interactionsEnabled = true
const hs = series.columns.template.states.create('hover')
hs.properties.strokeWidth = 8
const bullet = series.bullets.push(new am4charts.CircleBullet())
And then the function that should find a specific column and set hover:
setHover(chart, id) {
let xPosition
chart.series.each(series => {
if (!xPosition) {
const data = series.data.find(d => d.meta && d.meta.id === id)
if (!data) {
return
}
xPosition = chart.xAxes.getIndex(0).dataItems.values.findIndex(v => v.category === data.x)
}
const column = series.columns.getIndex(xPosition)
if (column) {
column.isHover = true
}
})
}
While this works, I'd prefer to identify the column directly instead of going by the category axis position. This would make more sense to me:
setHover(chart, id) {
chart.series.each(series => {
const column = series.columns.values.find(column => column.dataItem.meta.id === id)
if (column) {
column.isHover = value
}
})
}
Or, could it be done with adapter instead?
What's the most straight forward way?

sapui5 odata value xml content pretty

I have to achive something like this with multiple types of icons and colors so not all the icons in the column should be like that it could be red-icon-status-error or green-icon-status-success in base of oData values.
here is my code:
var jsonModel = new sap.ui.model.json.JSONModel();
var Source;
var clr;
jsonModel.setData(oData);..
for (var i = 0; i < oData.results.length; i++) {
iconSource = oData.results[i].ST;
switch (iconSource) {
case 'E':
{
Source = "sap-icon://status-error";
clr = "red";
}
break;
case 'S':
{
Source = "sap-icon://status-completed";
clr = "green";
}
break;
default:
{
Source = "sap-icon://status-critical";
clr = "grey";
}
break;
}
var jsonModel = new sap.ui.model.json.JSONModel(); //set new json model
jsonModel.setData(oData);//set the json
var view = that.getView();//get view
}//i close the for loop
var exempletable = sap.ui.getCore().byId(view.createId('tableviewid'));
var statusLabel = new sap.m.Label();
statusLabel.setText("Stat");
var statusColumn = new sap.ui.table.Column({
label: statusLabel,
template: new sap.ui.core.Icon({
src : Source,
color : clr
}),
width: "40px"
});
exempletable.insertColumn(statusColumn, 0);//here insteed of 0 it should be something like 0+i?
exempletable.setModel(jsonModel);//set model
exempletable.bindRows("/results");//bind rows
exempletable.setVisibleRowCount(10);
exempletable.setEnableSelectAll(false);
exempletable.setSelectionMode(sap.ui.table.SelectionMode.SingleSelectMaster);
exempletable.setNavigationMode(sap.ui.table.NavigationMode.Scrollbar);
});
},
So to reasume how do I loop in order to achive what I want, It's my logic good?
Instead of creating a new table in the controller you should init the table in the corresponding view. In your table item template you can format the values with a formatter function.
For formatter function example, check out following link:
https://sapui5.hana.ondemand.com/explored.html#/sample/sap.m.tutorial.walkthrough.23/code
You first do the Model binding in the table and setup the desired property to use the formatter function, the logic of the state handling is defined in the formatter controller (e.g. returns some value for one case).
I'm aussuming you initiallized your model with a given model name and you have knowledge about sapui5 bindings
var oExampleItemTemplate = new sap.m.ColumnListItem("idexampletemplate", {
unread: false,
cells: [
new sap.m.StandardListItem({
// The code after the comma within the title brackets calls the formatter function
title: "{parts: [ {path: 'your_model_name>property_name'} ], formatter: '<resourceroot.path.to.formatter.class.convertValueIntoMaterialGroup'}",
description: "{your_model_name>property_name}",
adaptTitleSize: false,
iconInset: true
})
]
}),
The above code is written for a javascript view, the example for an xml view you can find in the link pasted above.
Best regards

Kendo UI Grid - Excel Export with hidden columns and custom formatting

I'm attempting to use the Grid component's built-in support for exporting to excel, applying custom cell formatting as shown in these Telerik docs:
http://docs.telerik.com/kendo-ui/controls/data-management/grid/how-to/excel/cell-format
The approach using hard-coded row / cell indexes in the export comes with a rather obvious issue when exporting a grid with a prior hidden column displayed - best way to reproduce is to refer to this jsfiddle:
https://jsfiddle.net/3anqpnqt/1/
Run fiddle
Click export to excel - observe custom number formatting
Unhide subcategory column (using column menu)
Click export to excel - observe custom number formatting on column 2 which is now 'subcategory'
With reference to this code in the fiddle:
$("#grid").kendoGrid({
toolbar: ["excel"],
excel: {
fileName: "Grid.xlsx",
filterable: true
},
columns: [
{ field: "productName" },
{ field: "category" },
{ field: "subcategory", hidden: true },
{ field: "unitPrice"}
],
dataSource: [
{ productName: "Tea", category: "Beverages", subcategory: "Bev1", unitPrice: 1.5 },
{ productName: "Coffee", category: "Beverages", subcategory: "Bev2", unitPrice: 5.332 },
{ productName: "Ham", category: "Food", subcategory: "Food1", unitPrice: -2.3455 },
{ productName: "Bread", category: "Food", subcategory: "Food2", unitPrice: 6 }
],
columnMenu: true,
excelExport: function(e) {
var sheet = e.workbook.sheets[0];
for (var rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
var row = sheet.rows[rowIndex];
var numericFormat = "#,##0.00;[Red](#,##0.00);-";
for (var cellIndex = 0; cellIndex < row.cells.length; cellIndex++) {
var cell = row.cells[cellIndex];
if (row.type === "data") {
if (cellIndex == 2) { // how are we able to identify the column without using indexes?
cell.format = numericFormat;
cell.hAlign = "right";
}
}
}
}
}
});
What I need to be able to do is identify the cell as the 'unitPrice' and apply the format, but inspection of the object model within the excelExport handler doesn't give me any way to make this link. In my real application, I have several custom formats to apply (percentages, n0, n2 etc) so it's not as simple as going $.isNumeric(cell.value) or otherwise.
Update
I also need the solution to work with column / row groups, which generate additional header rows / columns in the Excel model.
It looks like row[0] is the header row, so you could try changing
if (cellIndex == 2) {
to
if (sheet.rows[0].cells[cellIndex].value == "unitPrice") {
EDIT:
Seems to work with column group: https://jsfiddle.net/dwosrs0x/
Update:
The object model for worksheet is not the most clear. The first row does seem to be a "master" header row in the various scenarios that I looked at. Here is something that seems to work if unitPrice is not in a grouping. If unitPrice is in a grouping, then something more complicated involving the group header (row[1]) might be possible. The puzzle is to find out what position the desired column will eventually occupy.
var header = sheet.rows[0];
var upIndex = -1;
var upFound = false;
for (var cellIndex = 0; cellIndex < header.cells.length; cellIndex++) {
if ('colSpan' in header.cells[cellIndex])
upIndex = upIndex + header.cells[cellIndex].colSpan;
else
upIndex = upIndex + 1;
if (header.cells[cellIndex].value == "unitPrice") { // wot we want
upFound = true;
break;
}
}
for (var rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
var row = sheet.rows[rowIndex];
if (row.type === "data" && upFound) {
var cell = row.cells[upIndex];
cell.format = numericFormat;
cell.hAlign = "right";
}
}
fiddle with groups - https://jsfiddle.net/dwosrs0x/4/
fiddle with straightforward grid (to prove it still works) - https://jsfiddle.net/gde4nr0y/1/
This definitely has the whiff of "bodge" about it.

Extjs 4 disable sort if grid is empty

Hello stackoverflow community,
is it somehow possible to disable the sorting mechanism in a grid for every column on a condition? Like...
if the grid hasn't any data loaded,
the sorting should be disabled,
else enabled.
I have the problem that if there is no data and you click on a column to sort, the remote sorting mechanism, will start loading the whole data and sorts it, too ...
This behaviour isn't needed or wished, so I want to disable the sorting possibility.
Your help is appreciated.
Thanks in advance and have a nice day.
This is a bit of a hack, but seems to work OK:
http://jsfiddle.net/q43HC/6/
var data = [{
data1: 'test',
data2: 'test'
}, {
data1: 'test2',
data2: 'test2'
}];
var store = Ext.create('Ext.data.Store', {
fields: ['data1', 'data2'],
data: data
});
Ext.define('SampleGrid', {
extend: 'Ext.grid.Panel',
store: store,
height: 250,
width: 400,
title: 'My Window',
columns: [{
text: 'test',
dataIndex: 'data1'
}, {
text: 'test2',
dataIndex: 'data2'
}],
bbar: [{
text: 'Clear Store',
handler: function() {
store.removeAll();
var grid = this.up('grid'),
cols = grid.query('gridcolumn'),
i = 0,
len = cols.length;
for (; i < len; i++) {
cols[i].doSort(null);
cols[i].__toggleSortState = cols[i].toggleSortState;
cols[i].toggleSortState = function() {};
}
}
}, {
text: 'Reload Store',
handler: function() {
store.loadData(data);
var grid = this.up('grid'),
cols = grid.query('gridcolumn'),
i = 0,
len = cols.length;
for (; i < len; i++) {
if (cols[i].__toggleSortState) {
cols[i].toggleSortState = cols[i].__toggleSortState;
}
}
}
}],
renderTo: Ext.getBody()
});
Ext.onReady(function() {
var grd = new SampleGrid();
});
I am just changing the sort state when the data is removed in order to remove any current sorting then replacing the toggleSortState function with an empty one so clicking the header will not sort the column. When reloading the store I put the function back.. You will have to adapt this to your project, but could create a store aware grid with similar logic.
You can do this globally by overriding the Ext.data.Store.sort method. The system I was working on uses remoteSort and hence hits the server everytime the user clicks the column header to sort, even if the grid itself is empty, pretty much same with your problem.
This is the code that you only need to declare in a single location (ie. your ext-overrides file or commons file), instead of in every single grid:
Ext.define('Ext.overrides.data.Store', {
override: 'Ext.data.Store',
sort: function() {
//prevents the grid from submitting a request if store is empty, for remote sort
if (this.count() > 0) {
this.callParent(arguments);
}
}
});
I have written the following function to achieve the same solution:
function disableColumnSorting(disable){
var grid = Ext.getCmp('billRecordGrid'),
cols = grid.query('gridcolumn'),
colLength = cols.length,
i = 0;
for(i; i < colLength; i++) {
if (disable) {
cols[i].sortable= false;
} else {
cols[i].sortable= true;
}
}
}
Thanks to drew630, you gave me a helpful hint, so I could solve my problem on my own.
If you do not want anything to happen when the grid is empty, you could put this in the store of the grid:
listeners: {
beforeload: function() {
return false when my conditions is met.;
}
}
This way your store will not load and nothing will happen. This is also handy when you have a pager component on the grid and where your server expects e.g. extraParams that are not yet set. If you expect extraParams, and when not yet set, the user clicks the refresh on the pager, you end up with exceptions. But with this check, you can prevent a call to the back-end if conditions are not met.
I sometimes set my api.read URL to undefined, (in cases where the store needs extraParams that are not yet set) and only when those params are available, I also set the URL (with a call in the store itself where the url is already set e.g. activateRead(). In the beforeload, I then test if the api.read is undefined or not.
Hope it helps.
Regards
Lawrende

jqgrid: several questions - matrix display

I have data of matrix stored in table as below tables:
MatrixDimensions - MatrixId, NoOfRows, NoOfCol
MatrixValues - MatrixId, RowNo, ColNo, Value
How can I make jqGrid to take no. of rows & columns dynamically
and also display the serialized data in matrix? Is there a direct way or will I have to implement for loops to upload the data in matrix?
Can I display rows as columns and columns as rows (so having column headers vertically aligned)?
Can I enable only inline editing and disable form based editing?
I just wrote the answer to another question where I described how to create the grid with dynamic number of columns (number of rows is always dynamic in jqGrid). It seems to me this way you can display any matrix. In you case you can probably make the code simpler because you can use generic column names like "1", "2", etc. (or "Col. 1", "Col. 2", etc.) and so on.
I modified the code so that it uses array of arrays (matrix) instead of the array on objects with named properties. So jqGrid will looks like this:
or this:
depending on the input JSON data.
The full demo can be found here. The full JavaScript code of the demo you can find below:
var mygrid=jQuery("#list"),
cmTxtTemplate = {
width:40,
align:"center",
sortable:false,
hidden:true
}, currentTemplate = cmTxtTemplate, i,
cm = [], maxCol = 30, dummyColumnNamePrefix = "", //"Col. ",
clearShrinkToFit = function() {
// save the original value of shrinkToFit
var orgShrinkToFit = mygrid.jqGrid('getGridParam','shrinkToFit');
// set shrinkToFit:false to prevent shrinking
// the grid columns after its showing or hiding
mygrid.jqGrid('setGridParam',{shrinkToFit:false});
return orgShrinkToFit;
},
setGridWidthAndRestoreShrinkToFit = function(orgShrinkToFit,width) {
// restore the original value of shrinkToFit
mygrid.jqGrid('setGridParam',{shrinkToFit:orgShrinkToFit});
mygrid.jqGrid('setGridWidth',width);
},
dummyTestRegex = new RegExp(dummyColumnNamePrefix+"(\\d)+"),
counter = 1;
// Add dummy hidden columns. All the columns has the same template
for (i=0;i<maxCol;i++) {
cm.push({name:dummyColumnNamePrefix+(i+1),template:currentTemplate});
}
mygrid.jqGrid({
url:'Matrix1.json',
datatype: "json",
// colNames will be set based on the properties for JSON input
colModel:cm,
height:"auto",
rownumbers:true,
loadonce:true,
gridview: true,
rowNum: 1000,
sortname:"",
jsonReader: {
cell: "",
id: function (obj) {
return "id"+counter++;
},
page: function (obj) {
var rows = obj.rows, colModel = mygrid[0].p.colModel,
cmi, width = 0, iFirstDummy, cols, orgShrinkToFit,
showColNames = [], hideColNames = [];
if (typeof(rows) === "undefined" || !(rows.length>0)) {
// something wrong need return
return obj.page;
}
// find the index of the first dummy column
// in the colModel. If we use rownumbers:true,
// multiselect:true or subGrid:true additional
// columns will be inserted at the begining
// of the colModel
iFirstDummy = -1;
for(i=0;i<colModel.length;i++) {
cmi = colModel[i];
if (dummyTestRegex.test(cmi.name)) {
iFirstDummy = i;
break;
}
}
if (iFirstDummy === -1) {
// something wrong need return
return obj.page;
}
orgShrinkToFit = clearShrinkToFit();
// we get the first row of the JSON data
cols = rows[0].length;
// fill the list of unused columns
for(i=0;i<colModel.length;i++) {
cmi = colModel[i];
if (i<iFirstDummy+cols) {
cmi.width = currentTemplate.width;
showColNames.push(cmi.name);
} else {
hideColNames.push(cmi.name);
}
}
mygrid.jqGrid('showCol',showColNames);
mygrid.jqGrid('hideCol',hideColNames);
setGridWidthAndRestoreShrinkToFit(orgShrinkToFit,
cols*currentTemplate.width);
return obj.page;
}
}
});
$("#readJson1").click(function() {
mygrid.jqGrid('setGridParam',
{datatype:'json',page:1,url:'Matrix1.json'})
.trigger('reloadGrid');
});
$("#readJson2").click(function() {
mygrid.jqGrid('setGridParam',
{datatype:'json',page:1,url:'Matrix2.json'})
.trigger('reloadGrid');
});
The simplest way to transpose the matrix (reflect it over its main diagonal) is on the server. If you can't do this, you can create and fill the transposed matrix inside of page function (see my code above) and just replace the row part of the obj with the transposed matrix.

Resources