Handsontable 7.4 dropdown cell with falsy value (0) shows placeholder - handsontable

I am looking for a way to display the numeric value 0 in a dropdown list that also includes placeholder text when the cell is empty. Currently, if 0 is selected the placeholder text shows through. I'm hoping for a built-in option and I'd like to avoid casting the number to string and back if I can (that would tear up my current validation scheme). The following example is modified from the HandsOnTable dropdown docs. The 'Chassis Color' column contains the issue.
jsfiddle:
https://jsfiddle.net/y3pL0vjq/
snippet:
function getCarData() {
return [
["Tesla", 2017, "black", "black"],
["Nissan", 2018, "blue", "blue"],
["Chrysler", 2019, "yellow", "black"],
["Volvo", 2020, "white", "gray"]
];
}
var
container = document.getElementById('example1'),
hot;
hot = new Handsontable(container, {
data: getCarData(),
colHeaders: ['Car', 'Year', 'Chassis color', 'Bumper color'],
columns: [
{},
{type: 'numeric'},
{
type: 'dropdown',
placeholder: "blah",
source: [null, 0, 1, 2, 3]
},
{
type: 'dropdown',
source: ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white']
}
]
});

The best way I found to handle this dropdown list of numbers is to omit the "type" attribute and specify the editor and validator as 'autocomplete. Then make a custom renderer to merge the NumericRenderer functionality with the autocomplete dropdown list.
To finalize the similar look and feel of the native dropdown function, you then add "strict: true" and "filter: false", as explained in the dropdown docs.
Internally, cell {type: "dropdown"} is equivalent to cell {type: "autocomplete", strict: true, filter: false}.
Dropdown Docs
Example:
function getCarData() {
return [
["Tesla", 2017, null, "black"],
["Nissan", 2018, 0, "blue"],
["Chrysler", 2019, 1, "black"],
["Volvo", 2020, 2, "gray"]
];
}
var
container = document.getElementById('example1'),
hot;
function myRenderer(instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.NumericRenderer.apply(this, arguments);
td.innerHTML += '<div class="htAutocompleteArrow">▼</div>'
}
hot = new Handsontable(container, {
data: getCarData(),
colHeaders: ['Car', 'Year', 'Chassis color', 'Bumper color'],
columns: [
{},
{type: 'numeric'},
{
editor: 'autocomplete',
validator: 'autocomplete',
renderer: myRenderer,
strict: true,
filter: false,
placeholder: "blah",
source: [null, 0, 1, 2, 3]
},
{
type: 'dropdown',
source: ['yellow', 'red', 'orange', 'green', 'blue', 'gray', 'black', 'white']
}
]
});

Related

jqGrid subGrid how to hide "+" expand icon if we don't have data sub grid

When i don't have any data in subgrid i am getting empty grid in subgrid. Also need to hide the expand icon. Below is the code i used.
$(document).ready(function() {
'use strict';
var myData = [
{
id: "10",
c1: "My Value 1",
c2: "My Value 1.1",
subgridData: [
{ id: "10", c1: "aa", c2: "ab" },
{ id: "20", c1: "ba", c2: "bb" },
{ id: "30", c1: "ca", c2: "cb" }
]
},
{
id: "20",
c1: "My Value 2",
c2: "My Value 2.1",
subgridData: [
{ id: "10", c1: "da", c2: "db" },
{ id: "20", c1: "ea", c2: "eb" },
{ id: "30", c1: "fa", c2: "fb" }
]
},
{
id: "30",
c1: "My Value 3",
c2: "My Value 3.1"
}
],
$grid = $("#list"),
mainGridPrefix = "s_";
$grid.jqGrid({
datatype: "local",
data: myData,
colNames: ["Column 1", "Column 2"],
colModel: [
{ name: "c1", width: 180 },
{ name: "c2", width: 180 }
],
rowNum: 10,
rowList: [5, 10, 20],
pager: "#pager",
gridview: true,
ignoreCase: true,
sortname: "c1",
viewrecords: true,
autoencode: true,
height: "100%",
idPrefix: mainGridPrefix,
subGrid: true,
subGridRowExpanded: function (subgridDivId, rowId) {
var $subgrid = $("<table id='" + subgridDivId + "_t'></table>"),
pureRowId = $.jgrid.stripPref(mainGridPrefix, rowId);
$subgrid.appendTo("#" + $.jgrid.jqID(subgridDivId));
$subgrid.jqGrid({
datatype: "local",
data: $(this).jqGrid("getLocalRow", pureRowId).subgridData,
colModel: [
{ name: "c1", width: 178 },
{ name: "c2", width: 178 }
],
height: "100%",
rowNum: 10000,
autoencode: true,
autowidth: true,
gridview: true,
idPrefix: rowId + "_"
});
$subgrid.closest("div.ui-jqgrid-view")
.children("div.ui-jqgrid-hdiv")
.hide();
}
});
$grid.jqGrid("navGrid", "#pager", {add: false, edit: false, del: false});
});
My output like below screenshot. How to remove the expand icon and subgrid if we don't have any data for subgrid.
Is there any way to achieve this behavior. My output like below.
The solution of the problem depends on the version and the fork of jqGrid, which you use. I develop free jqGrid fork and have implemented hasSubgrid callback, which I described in the answer (see the demo).
The items of your input data contains subgridData property as the array of subgrid data. Thus one should create the subgrid only if subgridData property is defined and subgridData.length > 0. Thus you need just to upgrade to the current version of jqGrid (4.13.4 or 4.13.5pre) and to add the option
subGridOptions: {
hasSubgrid: function (options) {
// the options contains the following properties
// rowid - the rowid
// iRow - the 0-based index of the row
// iCol - the 0-based index of the column
// data - the item of the data, with the data of the row
var subgridData = options.data.subgridData;
return subgridData != null && subgridData.length > 0;
}
}
to the main grid. The callback subGridOptions.hasSubgrid will be called during building the grid data, thus it works very effective like rowattr, cellattr and custom formatters.

include two series from database in a highchart chart

I would like to include a series to my existing chart.
daytime = new Highcharts.Chart({
chart: {
renderTo: 'daytime_div',
defaultSeriesType: 'areaspline',
events: {
load: getData()
}
},
plotOptions: {
series: {
fillOpacity: 0.1,
lineWidth: 4,
marker: {
radius: 5,
lineWidth: 1,
lineColor: "#FFFFFF"
}
}
},
tooltip: {
formatter: function () {
var s = [];
$.each(this.points, function (i, point) {
s.push('<span style="font-size:10px;">' + point.key + '</span><br/><strong>' + point.series.name + '</strong> : ' + point.y + '</span>');
});
return s.join('<br/>');
},
shared: true,
useHTML: true
},
credits: false,
title: false,
exporting: false,
legend: {
itemDistance: 50,
itemStyle: {
color: '#333'
}
},
xAxis: {
labels: {
staggerLines: 2
}
},
yAxis: {
gridLineColor: "#e7e7e7",
title: {
text: ''
},
labels: {
x: 15,
y: 15,
style: {
color: "#999999",
fontSize: "10px"
}
},
},
series: [{
name: 'Daily',
color: "#b18eda",
data: ddata
}]
});
function getData() {
$.ajax({
url: '...',
type: "POST",
contentType: "application/json; charset=utf-8",
data: data,
success: function (f) {
var categories = [];
var series_data = [];
$.each(f.d, function (i, e) {
categories.push(e.hour);
series_data.push(parseInt(e.numa));
});
daytime.xAxis[0].setCategories(categories);
daytime.series[0].setData(series_data);
},
cache: false
});
}
The data I get from my database looks like this:
hour, numa
12 AM 1
1 AM 0
2 AM 0
3 AM 0
4 AM 0
This shows one line in the chart which is fine. I would like to add a second line that will come from a different query. The second line data will look like:
hour, numa
12 AM 0
1 AM 12
2 AM 3
3 AM 2
4 AM 2
Does anyone knows how could I include this into my second series? I have seen the sample in high charts on how to add more series. Static is pretty simple but getting the data dynamically make it more complicated to figure it out.
I am trying to find a way to add 2 series to my getData() function. Any idea will be appreciate it thanks.
It is explained clearly in the fiddle of the document which you shared on how to add multiple series.
series: [{
name: 'Tokyo',
data: [7.0, 6.9, 9.5, 14.5, 18.2, 21.5, 25.2, 26.5, 23.3, 18.3, 13.9, 9.6]
}, {
name: 'New York',
data: [-0.2, 0.8, 5.7, 11.3, 17.0, 22.0, 24.8, 24.1, 20.1, 14.1, 8.6, 2.5]
}, {
name: 'Berlin',
data: [-0.9, 0.6, 3.5, 8.4, 13.5, 17.0, 18.6, 17.9, 14.3, 9.0, 3.9, 1.0]
}, {
name: 'London',
data: [3.9, 4.2, 5.7, 8.5, 11.9, 15.2, 17.0, 16.6, 14.2, 10.3, 6.6, 4.8]
}]
You can pass multiple series in array and the chart can be generated.
EDIT-1
If data from different series use this fiddle.
var myComments=["First input","second comment","another comment","last comment"]
var dataValues = [29.9, 71.5, 194.1, 129.2];
var dataValues2 = [194.1, 95.6, 194.1, 29.9];
var categories = ['Jan', 'Feb', 'Mar', 'Apr'];
var n=['tooltip1','tooltip2','tooltip3','tooltip4'];
$(function () {
$('#container').highcharts({
chart: {},
tooltip: {
formatter: function () {
var serieI = this.series.index;
var index = categories.indexOf(this.x);
var comment = myComments[index];
return '-->'+comment;
}
},
xAxis: {
categories: categories
},
series: [{
data: dataValues
}, {
data: dataValues2
}]
});
});
which results in the below graph
Well you can use $.when() and load there all your ajax and in $.then() initialise chart. Second solution is prepare your query to database and return all data in single json.

Handsontable checkbox's not working

Real simple, I've been trying to get the checkbox type to render on my list, but all I get is the value "no." Here's my settings object. Am I doing something wrong? The list renders perfectly and works properly in terms of conditional coloring, etc., just no checkboxes. HELP! and thank you.
settings = {
data: bulkListData
,dataSchema: {name: {first: null, last: null}, email: null,status: null,action: null}
,colHeaders: ['First Name', 'Last Name', 'Email','Status','Action']
,columns: [
{data: 'name.first'},
{data: 'name.last'},
{data: 'email'},
{data: 'status'},
{data: 'action'
,type: 'checkbox'
,checkedTemplate: 'yes'
,uncheckedTemplate: 'no'
}
]
,colWidths:[200,200,300,120,120]
,startRows: 5
,startCols: 5
,minRows: 5
,minCols: 5
,maxRows: 10
,maxCols: 5
,minSpareRows: 5
,autoWrapRow:true
,contextMenu: true}
I put your sample code in a fiddle and it works for me.
The only thing I needed was to fill in the bulkListData accordingly, otherwise everything is exactly like yours. Perhaps you are making the mistake exactly there - are your action properties in this array in the form of yes/no string?
I have a renderer that changes the color of a column. When this renderer is used the check boxes change to 'yes'/'no'.
When the renderer is not used the checkboxes show.
$(document).ready(function () { function getCompData() {
return [
{Comp: "Annually", year: 2006, Retirement: 'yes'},
{Comp: "Monthly", year: 2008, Retirement: 'yes'},
{Comp: "Quarterly", year: 2011, Retirement: 'no'},
{Comp: "Semi-Annually", year: 2004, Retirement: 'yes'},
{Comp: "Semi-Monthly", year: 2011, Retirement: 'no'}
];}function cellColorRenderer(instance, td, row, col, prop, value, cellProperties) {
Handsontable.TextCell.renderer.apply(this, arguments);
if (col === 1) {
td.style.textAlign = 'right';
td.style.backgroundColor = "#ccffcc";
}
}var example2 = document.getElementById('example2'); var hot2 = new Handsontable(example2,{ data: getCompData(),
startRows: 7,
startCols: 4,
colHeaders: ["Comp", "Year", "401K"],
colWidths: [120, 50, 60],
columnSorting: true,
columns: [
{
data: "Comp"
},
{
data: "year",
type: 'numeric'
},
{
data: "Retirement",
type: "checkbox",
checkedTemplate: 'yes',
uncheckedTemplate: 'no'
}
], cells:
function (row, col, prop) {
var cellProperties = {};
cellProperties.renderer = cellColorRenderer;
return cellProperties;
}, }); });
Here is the code in jsfiddle
http://jsfiddle.net/w42cp1y8/1/
Just use CheckboxRenderer instead TextRenderer:
$element.handsontable( {
cells: function( row, col, prop ) {
return {
renderer: function( instance, td, row, col, prop, value, cellProperties ) {
Handsontable.renderers.CheckboxRenderer.apply( this, arguments );
td.style.backgroundColor = value ? 'red' : 'white';
td.style.textAlign = 'center';
},
type: 'checkbox'
};
}
} );
jExcel is an alternative to handsontable. The example below is using a checkbox column type:
data = [
['Brazil', 'Classe A', 'Cheese', 1, '2017-01-12'],
['Canada', 'Classe B', 'Apples', 1, '2017-01-12'],
['USA', 'Classe A', 'Carrots', 1, '2017-01-12'],
['UK', 'Classe C', 'Oranges', 0, '2017-01-12'],
];
$('#my').jexcel({
data:data,
colHeaders: [ 'Country', 'Description', 'Type', 'Stock', 'Next purchase' ],
colWidths: [ 300, 80, 100, 60, 120 ],
columns: [
{ type: 'text' },
{ type: 'text' },
{ type: 'dropdown', source:[ {'id':'1', 'name':'Fruits'}, {'id':'2', 'name':'Legumes'}, {'id':'3', 'name':'General Food'} ] },
{ type: 'checkbox' },
{ type: 'calendar' },
]
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/jexcel/1.2.2/css/jquery.jexcel.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jexcel/1.2.2/js/jquery.jexcel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jexcel/1.2.2/js/jquery.jcalendar.min.js"></script>
<div id="my"></div>

Is it possible to have reqular bar and stacked bar in the same jqPlot chart?

I am trying to build a bar chart where 1st series represent the revenue and the next three represent different kind of expenses. So 1st series to be a single bar and the rest three series as stacked bar. Here is my code for the same.
var s0 = [15, 17, 19, 21];
var s1 = [2, 6, 7, 10];
var s2 = [7, 5, 3, 4];
var s3 = [14, 9, 3, 8];
var ticks = ['May', 'June', 'July', 'August'];
var plot3 = $.jqplot('chart1', [s0, s1, s2, s3], {
stackSeries: true,
animate: true,
seriesDefaults: {
renderer: $.jqplot.BarRenderer,
pointLabels: {
show: true,
},
rendererOptions: {
fillToZero: true,
barMargin: 30,
barWidth: 50,
barPadding: 5,
barDirection: 'vertical'
},
},
series: [
{
disableStack: true,
label: 'Revenue'
},
{label: 'Expense1'}, {label: 'Expense2'}, {label: 'Expense3'}
],
axesDefaults: {
tickRenderer: $.jqplot.CanvasAxisTickRenderer,
tickOptions: {
fontSize: '13pt'
}
},
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks
},
yaxis: {
}
},
legend: {
show: true,
location: 'e',
placement: 'outside'
}
});
I have addded disableStack: true for the first series to exclude it from the stack but the chart still considers it as a part of the stack. Here is the output of my code.
Is there a way to fix this ? Thanks.
Yes. It is the order of the series you pass as argument that is not correct.
BEFORE the stacked series
AFTER the single bar series
and not viceversa...
So you have to move the first series as the last argument...
var plot3 = $.jqplot('chart', [s1, s2, s3, s0], {
and then you need to set the disableStack property on 'true' for the last series...
series: [
{label: 'Expense1'}, {label: 'Expense2'}, {label: 'Expense3',label: 'Revenue', disableStack: true}
],
...and you need to adjust the margins, widts and padding of the columns
as you prefer...

Load local JSON data in jQgrid without AddJsonRows

I'm using the method addJsonRows to add local data to a jQgrid. As this method disables the sorting I need another solution. One restriction: I can't set the url and fetch the data from the server because the data was passed through another component.
Underneath snippet enlightens the case. The commented line shows the restriction, I replaced it by defining a local variable to have a test case.
<script type="text/javascript" language="javascript">
function loadPackageGrid() {
// Get package grid data from hidden input.
// var data = eval("("+$("#qsmId").find(".qsm-data-packages").first().val()+")");
var data = {
"page": "1",
"records": "2",
"rows": [
{ "id": "83123a", "PackageCode": "83123a" },
{ "id": "83566a", "PackageCode": "83566a" }
]
};
$("#packages")[0].addJSONData(data);
};
$(document).ready(function() {
$("#packages").jqGrid({
colModel: [
{ name: 'PackageCode', index: 'PackageCode', width: "110" },
{ name: 'Name', index: 'Name', width: "300" }
],
pager: $('#packagePager'),
datatype: "local",
rowNum: 10000,
viewrecords: true,
caption: "Packages",
height: 150,
pgbuttons: false,
loadonce: true
});
});
</script>
I wonder how I could do this in an other (better) way to keep the sorting feature.
I tried something with the data option, without result.
I suppose that the same question is interesting for other persons. So +1 from me for the question.
You can solve the problem in at least two ways. The first one you can use datatype: "jsonstring" and datastr: data. In the case you need to add additional parameter jsonReader: { repeatitems: false }.
The second way is to use datatype: "local" and data: data.rows. In the case the localReader will be used to read the data from the data.rows array. The default localReader can read the data.
The corresponding demos are here and here.
I modified a little your data: filled "Name" column and included the third item in the input data.
Now you can use local paging, sorting and filtering/searching of the data. I included a little more code to demonstrate the features. Below you find the code of one from the demos:
$(document).ready(function () {
'use strict';
var data = {
"page": "1",
"records": "3",
"rows": [
{ "id": "83123a", Name: "Name 1", "PackageCode": "83123a" },
{ "id": "83432a", Name: "Name 3", "PackageCode": "83432a" },
{ "id": "83566a", Name: "Name 2", "PackageCode": "83566a" }
]
},
grid = $("#packages");
grid.jqGrid({
colModel: [
{ name: 'PackageCode', index: 'PackageCode', width: "110" },
{ name: 'Name', index: 'Name', width: "300" }
],
pager: '#packagePager',
datatype: "jsonstring",
datastr: data,
jsonReader: { repeatitems: false },
rowNum: 2,
viewrecords: true,
caption: "Packages",
height: "auto",
ignoreCase: true
});
grid.jqGrid('navGrid', '#packagePager',
{ add: false, edit: false, del: false }, {}, {}, {},
{ multipleSearch: true, multipleGroup: true });
grid.jqGrid('filterToolbar', { defaultSearch: 'cn', stringResult: true });
});
UPDATED: I decided to add more details about the differences between datatype: "jsonstring" and datatype: "local" scenarios because the old answer be read and voted by many readers.
I suggest to modify the above code a little to show better the differences. The fist code uses datatype: "jsonstring"
$(function () {
"use strict";
var data = [
{ id: "10", Name: "Name 1", PackageCode: "83123a", other: "x", subobject: { x: "a", y: "b", z: [1, 2, 3]} },
{ id: "20", Name: "Name 3", PackageCode: "83432a", other: "y", subobject: { x: "c", y: "d", z: [4, 5, 6]} },
{ id: "30", Name: "Name 2", PackageCode: "83566a", other: "z", subobject: { x: "e", y: "f", z: [7, 8, 9]} }
],
$grid = $("#packages");
$grid.jqGrid({
data: data,
datatype: "local",
colModel: [
{ name: "PackageCode", width: 110 },
{ name: "Name", width: 300 }
],
pager: "#packagePager",
rowNum: 2,
rowList: [1, 2, 10],
viewrecords: true,
rownumbers: true,
caption: "Packages",
height: "auto",
sortname: "Name",
autoencode: true,
gridview: true,
ignoreCase: true,
onSelectRow: function (rowid) {
var rowData = $(this).jqGrid("getLocalRow", rowid), str = "", p;
for (p in rowData) {
if (rowData.hasOwnProperty(p)) {
str += "propery \"" + p + "\" + have the value \"" + rowData[p] + "\n";
}
}
alert("all properties of selected row having id=\"" + rowid + "\":\n\n" + str);
}
});
$grid.jqGrid("navGrid", "#packagePager",
{ add: false, edit: false, del: false }, {}, {}, {},
{ multipleSearch: true, multipleGroup: true });
$grid.jqGrid("filterToolbar", { defaultSearch: "cn", stringResult: true });
});
It displays (see the demo)
One can see unsorted items in the same order like input data. The items of input data will be saved in internal parameters data and _index. getLocalRow method used in onSelectRow shows that items of internal data contains only properties of input items which names corresponds to name property of some jqGrid columns. Additionally unneeded _id_ property will be added.
On the other side the next demo which uses datatype: "local" displays sorted data and all properties inclusive complex objects will be still saved in the internal data:
The code used in the last demo is included below:
$(function () {
"use strict";
var data = [
{ id: "10", Name: "Name 1", PackageCode: "83123a", other: "x", subobject: { x: "a", y: "b", z: [1, 2, 3]} },
{ id: "20", Name: "Name 3", PackageCode: "83432a", other: "y", subobject: { x: "c", y: "d", z: [4, 5, 6]} },
{ id: "30", Name: "Name 2", PackageCode: "83566a", other: "z", subobject: { x: "e", y: "f", z: [7, 8, 9]} }
],
$grid = $("#packages");
$grid.jqGrid({
data: data,
datatype: "local",
colModel: [
{ name: "PackageCode", width: 110 },
{ name: "Name", width: 300 }
],
pager: "#packagePager",
rowNum: 2,
rowList: [1, 2, 10],
viewrecords: true,
rownumbers: true,
caption: "Packages",
height: "auto",
sortname: "Name",
autoencode: true,
gridview: true,
ignoreCase: true,
onSelectRow: function (rowid) {
var rowData = $(this).jqGrid("getLocalRow", rowid), str = "", p;
for (p in rowData) {
if (rowData.hasOwnProperty(p)) {
str += "propery \"" + p + "\" + have the value \"" + rowData[p] + "\"\n";
}
}
alert("all properties of selected row having id=\"" + rowid + "\":\n\n" + str);
}
});
$grid.jqGrid("navGrid", "#packagePager",
{ add: false, edit: false, del: false }, {}, {}, {},
{ multipleSearch: true, multipleGroup: true });
$grid.jqGrid("filterToolbar", { defaultSearch: "cn", stringResult: true });
});
So I would recommend to use datatype: "local" instead of datatype: "jsonstring". datatype: "jsonstring" could have some advantages only in some very specific scenarios.
Great advice, Oleg.
In my web app, I pre-loaded some JSON data which looked like this:
{
WorkflowRuns:
[
{
WorkflowRunID: 1000,
WorkflowRunName: "First record",
},
{
WorkflowRunID: 1001,
WorkflowRunName: "Second record",
}
],
UserInformation:
{
Forename: "Mike",
Surname: "Gledhill"
}
}
And here's the code I needed to create the jqGrid, just based on the WorkflowRuns part of this JSON:
var JSONstring = '{ WorkflowRuns: [ { WorkflowRunID: 1000, .. etc .. } ]';
$("#tblWorkflowRuns").jqGrid({
datatype: "local",
data: JSONstring.WorkflowRuns,
localReader: {
id: "WorkflowRunID",
repeatitems: false
},
...
});
This was a bit of trial and error though.
For example, jqGrid seemed to ignore datastr: JSONstring for me.
And notice how, with local data, I needed to use localReader, rather than jsonReader, otherwise it wouldn't set the row IDs properly.
Hope this helps.

Resources