handsontable is it possible to have comboboxes (dropdowns) on a row rather than a column? - handsontable

is it possible to have comboboxes (dropdowns) on a row rather than a column?
all the examples I've found talk about columns only, e.g.
http://docs.handsontable.com/0.15.0-beta6/demo-dropdown.html
I need a row of editable comboboxes instead, does anyone have any examples of how do achieve this, if it is even possible?

Yes what you want to do is use the cells option just like you would the columns. In this one you are supplied with row,col so you would do something like:
cells: function(row,col) {
if (row == 0) {
// checkbox logic
}
}
And that should be all!
JsFiddle with example

#ZekeDroid pointed me in the right direction to the answer for what I actually asked. Adding the code here so you don't have to waste time learning to do it for yourself.
function getCarData() {
return [
['dog', 'dog', 'dog','dog'], ["Something", 2013, "blue", "blue"], ["Else", 2014, "yellow", "black"], ["Here", 2015, "white", "gray"]];
}
var
container = document.getElementById('example1'),
hot;
hot = new Handsontable(container, {
data: getCarData(),
colHeaders: ['Car', 'Year', 'Chassis color', 'Bumper color'],
cells: function (row, col, prop) {
var cellProperties = {};
if (row === 0) {
cellProperties.type = 'dropdown';
cellProperties.source = ['yellow', 'dog', 'cat'];
}
return cellProperties;
}
});

Related

DataTable in Flutter, Sorting multiple columns?

This question is actually sort of simple, but: Is it possible to sort a DataTable on more than one column?
So that the user can decide if it should be sorted on for example Name or Year?
If possible how do you implement it?
you can use onSort in every column like this
DataColumn(
label: Text('name'),
onSort: (columnIndex, sortAscending) {
setState(() {
if (columnIndex == _sortColumnIndex) {
_sortAsc = _sortNameAsc = sortAscending;
} else {
_sortColumnIndex = columnIndex;
_sortAsc = _sortNameAsc;
}
_persons.sort((a, b) => a.name.compareTo(b.name));
});
},
),

Cant get a grouped kendo ui column chart to hide when some items in group don't have a value

I've been trying to get a telerik kendo ui column chart to display grouped data but where the groups might not have entries for all possible values and I don't want to show space/empty columns in these empty cases.
Telerik dojo of problem
Is anyone aware of anyway to get this to work more like the screenshot below
Excel has grouped the data but doesn't display a column at all if the data is null/zero
I couldn't find a built-in way to do this, so I ended up just placing the bars manually by overriding the visual function. In my case, I only needed to move one bar and that bar will always be the same category, which made it a whole lot easier in that I only had to identify it by matching the category. I could then move it with a transform. You cannot move it by setting the coordinates because the visual has already been created.
It would be more complex to do this dynamically, but it's certainly possible. This may give someone a start in the right direction.
One downside of this method is that you must also place the labels manually, which I have also done below. You can override the visual function of the labels, as well, but no references to any other elements are passed with the event data. Note how the documentation says the sender field may be undefined; in my experience, this is always the case.
It also does not move the tooltip or the highlight. You could use the same method to move the highlight (override the visual function, though on the series instead of the seriesDefaults) and draw the tooltip manually while moving the highlight -- similar to how the method below draws the label while moving the column.
Telerik Dojo Example
$(document).ready(function () {
$("#chart").kendoChart({
legend: { visible: false },
tooltip: { visible: false },
categoryAxis: {
name: "categoryAxis",
categories: ["1", "2", "3"],
},
series: [
{
data: [1, 2, 3],
highlight: { visible: false },
},
{
data: [1.5, null, 3.5],
highlight: { visible: false },
}
],
seriesDefaults: {
type: "column",
labels: { visible: false },
visual: function (e) {
if (e.value === null) return;
var visual = e.createVisual();
var axisRect = e.sender.getAxis("categoryAxis").slot("2");
var group = new kendo.drawing.Group();
var label = new kendo.drawing.Text(e.value, [0, 0], {
font: "20px sans-serif",
fill: { color: "black" }
});
var lbox = label.clippedBBox();
label.position([
e.rect.origin.x + e.rect.size.width / 2 - lbox.size.width / 2,
e.rect.origin.y - label.bbox().size.height * 1.5
]);
group.append(visual, label);
if (e.category === "2") {
var x = (axisRect.origin.x + axisRect.size.width / 2) - e.rect.size.width / 2;
group.transform(kendo.geometry.transform().translate(x - e.rect.origin.x, 0));
}
return group;
},
}
});
});

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.

Handsontable change a column source

Is it possible to change the source in a Handsontable instance when inside an event?
Below is my code:
var container2 = $('#example2');
var hot2 = new Handsontable(container2, {
data: {},
minRows: 5,
colHeaders: ['Car', 'Year', 'Car Color'],
columns: [
{
type: 'autocomplete',
source: ['BMW', 'Chrysler', 'Nissan', 'Suzuki', 'Toyota', 'Volvo'],
strict: true,
allowInvalid: false
}, ,
{},
{
type: 'autocomplete',
source: ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white', 'purple', 'lime', 'olive', 'cyan'],
strict: true,
allowInvalid: false
}]
});
Handsontable.hooks.add('afterChange', afterChangedCallback, hot2);
function afterChangedCallback(p) {
console.log(p);
if (p[0][1] == 0) {
alert('This means the first column has changed, I now want to update the colors here');
}
}
When a user selects a different car brand, I only want to populate the dropdown of "Car Color" with certain colors. Thus, not all car brands has the same colors.
EDIT
I updated the callback function to this based on the accepted answer:
function afterChanged(p) {
console.log(p);
if (p[0][1] == 0) {
hot2.updateSettings({
cells: function (row, col, prop) {
if (row == p[0][0] && col == 2) {
var cellProperties = {};
cellProperties.source = ['red', 'yellow', 'blue'];
return cellProperties;
}
}
});
}
}
Yup, you can use the updateSettings method to change the source of an entire column or particular cell. You probably want per-cell so I would do:
hot.updateSettings({
cells: newCellDefinitionFunction()
})
Of course this new definition is up to you to figure out. It could just be returning the same cellProperties each time but check on some global array for what sources to use for which cells.

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