google.visualization.DataTable(JSON.parse(datastring)) is not working - angularjs

I am using google charts to display some data on the screen and on some button click. The data is loading from webapi call.
To simplyfy the issue, I made the data hardcoded in function itself.
The issue is when I call
google.visualization.DataTable(JSON.parse(datastring))
Message: Table has no columns.
it is returning empty datatable. I also tried with arrayToDatable but no use.
I got error with arrayToDataTable. here is it.
Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys
I have create a plunker for it.
http://plnkr.co/edit/pctIqoCWi3LhqxlgdnqM?p=preview
Can anyone have a look and let me know whats wrong with this.

when creating google.visualization.DataTable directly from json,
the json must be in a specific format
see --> Format of the Constructor's JavaScript Literal data Parameter
google.visualization.arrayToDataTable accepts an array of values, not objects...
[["ReportName","ReportTime"],["ABC",48],["XYZ",50]]
if you don't want to change the format of the results from the webapi call,
you'll need to transform the data for the chart
see following working snippet for an example...
google.charts.load('current', {
callback: function () {
var datastring = '{"PerformanceData" : [{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"XYZ","ReportTime":"50"}]}';
var jsonData = JSON.parse(datastring);
var chartData = [];
// load chart data
jsonData.PerformanceData.forEach(function (row, rowIndex) {
// column headings
var columns = Object.keys(row);
if (rowIndex === 0) {
chartData.push(columns);
}
// row values
var chartRow = [];
columns.forEach(function (column, colIndex) {
var chartCell = row[column];
if (colIndex > 0) {
chartCell = parseFloat(chartCell);
}
chartRow.push(chartCell);
});
chartData.push(chartRow);
});
var data = google.visualization.arrayToDataTable(chartData);
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
chart.draw(data, { width: 400, height: 240 });
},
packages:['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
EDIT
once the data table is built, use the group() method to aggregate the data
you can use one of the provided aggregation functions, or provide your own
google.visualization.data.avg
google.visualization.data.count
google.visualization.data.max
google.visualization.data.min
google.visualization.data.sum
see following working snippet...
google.charts.load('current', {
callback: function () {
var datastring = '{"PerformanceData" : [{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"XYZ","ReportTime":"50"},{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"XYZ","ReportTime":"50"},{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"XYZ","ReportTime":"50"},{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"XYZ","ReportTime":"50"}]}';
var jsonData = JSON.parse(datastring);
var chartData = [];
// load chart data
jsonData.PerformanceData.forEach(function (row, rowIndex) {
// column headings
var columns = Object.keys(row);
if (rowIndex === 0) {
chartData.push(columns);
}
// row values
var chartRow = [];
columns.forEach(function (column, colIndex) {
var chartCell = row[column];
if (colIndex > 0) {
chartCell = parseFloat(chartCell);
}
chartRow.push(chartCell);
});
chartData.push(chartRow);
});
var data = google.visualization.arrayToDataTable(chartData);
// group data
var dataGroup = google.visualization.data.group(
data, // data table
[0], // group by column
[{ // aggregation column
column: 1,
type: 'number',
aggregation: google.visualization.data.sum
}]
);
var chart = new google.visualization.PieChart(document.getElementById('chart_div'));
// use group data to draw chart
chart.draw(dataGroup, {
pieSliceText: 'value',
width: 400,
height: 240
});
},
packages:['corechart']
});
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Related

How to add rowCount in tooltip of google charts

I am using google chart to display my data on screen. Data is aggregated using using one of the column as shown below...
var dataGroup = google.visualization.data.group(
data, // data table
[0], // group by column
[
{ // aggregation column
column: 1,
type: 'number',
aggregation: google.visualization.data.avg
}
]
);
chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
chart.draw(dataGroup, $scope.getOptionsForChart());
Now what I want to do is add row count in tooltip.
THanks in advance.
there are no standard options for adding information to the tooltip,
you must replace the entire tooltip with your own custom one...
two things must be in place to use custom html tooltips...
1) must use the following chart option...
tooltip: {
isHtml: true
}
2) the tooltip column must have the following property...
p: {html: true}
see following working snippet...
an aggregation column is added for the count
then a DataView is used to convert the count column to a tooltip column
however, when using a DataView, for some reason the html column property is ignored
so when the chart is drawn, convert the DataView back to a DataTable,
chart.draw(view.toDataTable(), ...
this will allow the chart to recognize the column property...
google.charts.load('current', {
callback: function () {
var datastring = '{"PerformanceData" : [{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"XYZ","ReportTime":"50"},{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"XYZ","ReportTime":"50"},{"ReportName":"ABC","ReportTime":"48"},{"ReportName":"XYZ","ReportTime":"50"}]}';
var jsonData = JSON.parse(datastring);
var chartData = [];
// load chart data
jsonData.PerformanceData.forEach(function (row, rowIndex) {
// column headings
var columns = Object.keys(row);
if (rowIndex === 0) {
chartData.push(columns);
}
// row values
var chartRow = [];
columns.forEach(function (column, colIndex) {
var chartCell = row[column];
if (colIndex > 0) {
chartCell = parseFloat(chartCell);
}
chartRow.push(chartCell);
});
chartData.push(chartRow);
});
var data = google.visualization.arrayToDataTable(chartData);
// group data
var dataGroup = google.visualization.data.group(
data, // data table
[0], // group by column
[
{ // average
column: 1,
type: 'number',
aggregation: google.visualization.data.avg,
label: data.getColumnLabel(1)
},
{ // count
column: 1,
type: 'number',
aggregation: google.visualization.data.count
}
]
);
var view = new google.visualization.DataView(dataGroup);
view.setColumns([0, 1, {
type: 'string',
role: 'tooltip',
calc: function (dt, row) {
return '<div class="tooltip">' +
'<div><span>' + dt.getValue(row, 0) + '</span></div>' +
'<div><span>' + dt.getColumnLabel(1) + ' (avg): </span>' + dt.getValue(row, 1) + '</div>' +
'<div><span>Row Count: </span>' + dt.getValue(row, 2) + '</div>' +
'</div>';
},
p: {html: true}
}]);
var chart = new google.visualization.ColumnChart(document.getElementById('chart_div'));
// use group data to draw chart
chart.draw(view.toDataTable(), {
tooltip: {
isHtml: true
}
});
},
packages: ['corechart']
});
.tooltip {
font-size: 12pt;
padding: 8px;
}
.tooltip div {
padding: 4px;
}
.tooltip span {
font-weight: bold;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>

Why does my angular directed work on one table cell but none others?

I am using a ContextMenu directive within a kendo grid. I have made one change to it so I can include icons in the text (changed $a.text(text) to $a.html(text).
I have one in the first cell (I highjacked the hierarchical cell) that has row operations (add, clone& delete) and one on a span within each cell that changes the cell values operation (addition, subtraction, equals, etc...)
Both of these were working. I am unsure what I changed that stopped it from working because I last checked it several changes ago (I'm still locked out of TFS so I can't revert).
One change I made was to include a disabled/enabled check to the working contextMenu. I tried adding the same to the broken one and no dice.
I do perform a $compile on the working menu and the broken one is only included in the kendo field template.
If I must compile the field template (and I didn't need to before), how can this be done?
So here is some code.
working menu:
$scope.getRowContextMenu = function (event) {
var options =
[[
"<span class='fa fa-files-o'></span>Clone Rule", function (scope, cmEvent) {/*omitted for brevity*/}),rowContextDisableFunction]]
}
var setHierarchyCell = function (grid) {
var element = grid.element;
var hCells = element.find("td.k-hierarchy-cell");
hCells.empty();
var spanStr = "<span context-menu='getRowContextMenu()' class='fa fa-bars'></span>";
hCells.append($compile(spanStr)($scope));
var span = hCells.find("span.fa");
span.on('click', function (event) {
$(this).trigger('contextmenu', event);
});
}
kendo template:
var mutliFormTemplate = function (fieldName, type) {
var result = "";
result += "<span context-menu='getOperationContextMenuItems()' class='fa #= " + fieldName + "_Obj.OperationSymbol # type-" + type + "'> </span>\n";
/*The rest pertains to the cell value. excluded for brevity*/
return result;
}
$scope.getOperationContextMenuItems = function () {
//I trimmed this all the way down to see if I could get it working. Still no joy
return [
["test", function () { }, true]
];
}
Creating the kendo columns dynamically:
$scope.model = {
id: "RuleId",
fields: {}
};
$scope.fieldsLoaded = function (data, fields) {
var column = {}
$.each(fields, function () {
var field = this;
$scope.columns.push({
field: field.Name,
title: field.Name,
template: mutliFormTemplate(field.Name, "selector")
});
column[field.Name ] = { type: getFieldType(field.Type.BaseTypeId) }
});
$scope.model.fields = column;
}
Thanks for any and all help ^_^

Multiple dropdown selection in ag-grid (link Attached)

I need to have a column in ag-grid where i can select multiple values from dropdown. I just googled online to see if it is already implemented but i could find only one link.
https://gist.github.com/gaborsomogyi/00f46f3c0ee989b73c92
Can someone let me know how to implement it. show the full code as an example please.
Here is the code shared over there.
function agDropDownEditor(params, optionsName, optionsList) {
_.set(params.$scope, optionsName+'.optionsList', optionsList);
var html = '<span style="width:100%; display:inline-block" ng-show="!'+optionsName+'.editing" ng-click="'+optionsName+'.startEditing()">{{data.'+params.colDef.field+'}}</span> ' +
'<select style="width:100%" ng-blur="'+optionsName+'.editing=false" ng-change="'+optionsName+'.editing=false" ng-show="'+optionsName+'.editing" ng-options="item for item in '+optionsName+'.optionsList" ng-model="data.'+params.colDef.field+'">';
// we could return the html as a string, however we want to add a 'onfocus' listener, which is not possible in AngularJS
var domElement = document.createElement("span");
domElement.innerHTML = html;
_.set(params.$scope, optionsName+'.startEditing', function() {
_.set(params.$scope, optionsName+'.editing', true); // set to true, to show dropdown
// put this into $timeout, so it happens AFTER the digest cycle,
// otherwise the item we are trying to focus is not visible
$timeout(function () {
var select = domElement.querySelector('select');
select.focus();
}, 0);
});
return domElement;
}
Hope this helps, this is just a snippet of my code what i'm doing is I'm fetching from an array using map and then creating my object which is col and returning it and this will repeat till the last index of that array.
var col = {};
col.field = "fieldName";
col.headerName = "colName";
col.headerCellTemplate = function() {
var eCell = document.createElement('span');
eCell.field = obj.expr;
eCell.headerName = obj.colName;
eCell.innerHTML = "<select>"+"<option>"+
'Abc'+"</option>" +"<option>"+
'Xyz'+"</option>" +"</select>"
//$scope.dropDownTemplate;
var eselect = eCell.querySelector('select');
eselect.focus();
return eCell;
};
return col ;
}));

Resize column in SlickGrid

I have the following SlickGrid:
var eligibleProductsGrid = new recline.View.SlickGrid({
model:dataset,
el:'#selectorModal #selectorModalContainer #selectorModalGrid',
state:{
fitColumns:true,
hiddenColumns: ['id', 'mrid', 'distributedQuantity' ,'qMeasureUnit'],
gridOptions:{
enableColumnReorder:false,
gridIdCSS: arguments[0].gridIdCSS ? arguments[0].gridIdCSS: "eligpprodGs9999",
}
}
});
and i want to rezise the width of the third column.
I've tried doing this:
var cols = this.eligibleProductsGrid.getColumns();
cols[2].width = 520;
this.eligibleProductsGrid.setColumns(cols);
but i have an error saying that getColumns() is not a function.
Any ideas? Thanks!

KendoGrid/Angular: cannot create grid columns/data dynamically

In this plunk I have an empty grid (without columns). When I click on "Build Grid" I need to add columns (taken from an array) and also add a row to the table.
The problem is that the columns are not added to the grid, any ideas? If I try to refresh the grid, I get an undefined error.
HTML:
<button ng-click="buildGrid()">Build Grid</button>
<div kendo-grid="grid" k-options="gridOptions" k-data-source="ds"></div>
Javascript:
var app = angular.module("app", [ "kendo.directives" ]);
function MyCtrl($scope) {
$scope.ds = []
$scope.colsList = [{ name: "col1" },
{ name: "col2" },
{ name: "col3" },
{ name: "col4" }];
var gridCols = [];
$scope.gridOptions = {
columns: gridCols
};
$scope.buildGrid = function() {
$scope.data = {};
for (var x=0;x<$scope.colsList.length;x++) {
var col = {};
col.field = $scope.colsList[x].name;
col.title = $scope.colsList[x].name;
$scope.data[col.field] = "" + (1111 * (x+1));
gridCols.push(col);
}
// add one row to the table
$scope.ds.push($scope.data);
//$scope.grid.refresh();
};
}
You need to use k-rebind so that the grid reinitializes (you can't set the columns dynamically on an existing grid):
<div kendo-grid="grid"
k-options="gridOptions"
k-data-source="ds"
k-rebind="gridOptions"></div>
(demo)

Resources