Applying DataView on DataTable with duplicate values - javascript

I have a table and one of its columns has multiple duplicates. I want to filter all the rows that have the same value on the column at once. I tried to use the getFormattedValue() method which gets the value of a column and then I applied the usual code for DataView. When I click on the row, it disappears all the rows of the table except of the selected one and it doesn't filter all the rows with the duplicate value on the column. Here is my code so far:
var table = new google.visualization.Table(document.getElementById('chart_div'));
var items = " ";
table.draw(dataTable, {width: 1000, height: 300});
google.visualization.events.addListener(table, 'select',
function(event) {
var selection = table.getSelection();
var view = new google.visualization.DataView(dataTable);
for(i = 0; i < row.length; i++){
var items == dataTable.getFormattedValue(i, i);
if(items = "anti-social-behaviour"){
console.log("if statement");
view.setRows([selection[i].row]);
table.draw(view, []);
}
}
});
If anyone could spot the problem it wold be much appreciated. Thank you.

I see many problems with this code. First off, where is row coming from in this line?
for(i = 0; i < row.length; i++){
Second, you are testing the formatted value of (i, i) in the data set, which checks (0, 0), then (1, 1), then (2, 2), etc. instead of checking an entire row or column. Third, on these lines:
view.setRows([selection[i].row]);
table.draw(view, []);
You are setting the rows to be used in the view to the row property of the ith element in selection (which may be undefined, since there is nothing stopping i from growing larger than the length of selection). The setRows method sets the entire row set to use for the view, so each time you call that, you are setting the rows to (a maximum of) 1 row, and then drawing the table with the view, which is why you see only 1 row in the table.
If you want to filter the table to display only rows that have a value matching the value in the selected row, this is what you need to use:
google.visualization.events.addListener(table, 'select', function(event) {
var selection = table.getSelection();
if (selection.length) {
var filterView = new google.visualization.DataView(dataTable);
filterView.setColumns([{
type: 'string',
sourceColumn: 1, // set this column to be whatever column you want to check for duplicate values
calc: 'stringify'
}]);
var value = filterView.getValue(selection[0].row, 0);
var rows = filterView.getFilteredRows([{column: 0, value: value}]);
var view = new google.visualization.DataView(dataTable);
view.setRows(rows);
table.draw(view, []);
}
});

Related

(amCharts) The chart gets its data from a HTML table. How to update the legend if a new table row is dynamically added?

I have a HTML table that serves as the data provider for the chart. The table can be dynamically edited with a click of the button (I can add a new row to it).
I can update the chart each time a new row is added. However the legend remains the same, it only has three initial graphs. How can I update the legend alongside the chart?
Here is my fiddle: https://jsfiddle.net/yvzj8acd/2/
And here is the JS where I add new row to the table:
//////////////////////////////////
// This is where I update the chart
//////////////////////////////////
$(document).ready(function() {
var newtr = "<tr class='row1a'><th>Row 4</th><td>10000</td><td>20000</td><td>5000</td><td>15000</td><td>7500</td><td>10000</td></tr>"
var newtr2 = "<tr class='row1a'><th>Row 5</th><td>15000</td><td>30000</td><td>2000</td><td>10000</td><td>15500</td><td>7000</td></tr>"
var newtr3 = "<tr class='row1a'><th>Row 6</th><td>1000</td><td>25000</td><td>15000</td><td>7000</td><td>10000</td><td>8000</td></tr>"
$(".ganti").click(function(e) {
$('#dataTable').append(newtr, newtr2, newtr3);
generateChartData();
chart.dataProvider = chartData;
chart.validateData();
chart.animateAgain();
e.preventDefault();
});
});
Quick FYI, AmCharts.ready is equivalent to $(document).ready, so you can easily combine the two.
As for your question, you need to tweak your data and chart generation approach so that it can handle the dynamically added data. Right now, your setup is pretty much hard-coded to the first three rows and the new data is never added. You also need to update the chart and add additional graphs as needed when new rows are added.
The first thing I did was update your generate data method to dynamically pull all rows that contain data, rather than the current hardcoded method that grabs the first three rows:
function generateChartData() {
// initialize empty array
chartData = [];
// get the table
var table = document.getElementById('dataTable');
var years = table.rows[0].getElementsByTagName('th');
//get the rows with graph values. Since data rows always
//have a class that begin with "row", use that as the query selector
var rows = document.querySelectorAll("tr[class^='row']");
var row;
// iterate through the <td> elements of the first row
// and construct chart data out of other rows as well
for (var x = 0; x < years.length; x++) {
//set up the initial object containing the year
var dataElem = {
"year": years[x].textContent
};
//iterate through the other rows based on the current year column (x + 1) and add that value to the
//object
for (row = 0; row < rows.length; row++) {
dataElem[rows[row].cells[0].textContent] = rows[row].cells[x + 1].textContent
}
//append final object to chart data array
chartData.push(dataElem);
}
}
Next, I created a generateGraphsFromData method that takes the chart instance and chartData array. This method compares the valueFields found in the first element of the chartData array and the valueFields in the chart's graphs array and creates new graphs where there aren't any in the array. This works for both chart creation and update:
//update the chart's graphs array based on the the currently known valueFields
function generateGraphsFromData(chart, chartData) {
//get the chart graph value fields
var graphValueFields = chart.graphs.map(function(graph) {
return graph.valueField;
});
//create an array of new graph value fields by filtering out the categoryField
//and the currently known valueFields.
var newGraphValueFields = Object.keys(chartData[0]).filter(function(key) {
return key != chart.categoryField;
}).filter(function(valueField) {
return graphValueFields.indexOf(valueField) === -1;
});
//for each new value field left over, create a graph object and add to the chart.
newGraphValueFields.forEach(function(valueField) {
var graph = new AmCharts.AmGraph();
graph.title = valueField;
graph.valueField = valueField;
graph.balloonText = "Rp[[value]]";
graph.lineAlpha = 1;
graph.bullet = "round";
graph.stackable = false; // disable stacking
chart.addGraph(graph);
});
}
From there I just updated your ready method to call this function instead of setting the graphs manually, along with forcing the first two to be hidden:
// Create graphs
generateGraphsFromData(chart, chartData);
//default the other two graphs to hidden
chart.graphs[1].hidden = true;
chart.graphs[2].hidden = true;
Then I modified your click event to call the generateGraphs method as well:
$(".ganti").click(function(e) {
$('#dataTable').append(newtr, newtr2, newtr3);
generateChartData();
generateGraphsFromData(chart, chartData);
// ...
Updated fiddle. I also moved the AmCharts.ready method into a separate standalone function and called it into $(document).ready, since both are identical anyway. Feel free to tweak the logic if you want to default other new graphs to hidden or whatever.

Load array in Handsontable cell

While changing the values in one cell I have to load array of values (as drop down) in other cell.
I don't know how to load array in cell.
What I tried is:
afterChange: function(changes, source) {
if(!changes) {
return;
}
$.each(changes, function(index, element) {
var row = element[0];
var col = element[1];
var oldVal = element[2];
var newVal = element[3];
if(col==6) {
tsContainer.setDataAtCell(row, 1, pjtArray);
}
});
}
Here I used setDataAtCell method, It loads the array as string(comma separated).
And I tried
var arr = [['123'],['dfg'],['678'],['asd']];
tsContainer.populateFromArray(row, 1, arr);
But it load the array each element in each cell.
I have to display all element in one cell as dropdown.
In handsontbale column property we can set array as source. I need something like that.
Since the data is dynamically loaded I have to write this in afterChange event.
Please help me..
Your guess was correct, you need to change the property source of the column to modify the dropdown values.
Let's take the following initial data set :
myData = [
['source1', 'option1'],
['source1', 'option3'],
['source2', 'option5'],
['source2', 'option7']
],
As well as the following dropdown values :
selectSource = ['source1','source2'],
source1 = ['option1','option2','option3','option4'],
source2 = ['option5','option6','option7','option8'],
And let's say you want to modify the dropdown values of column 2 depending on the value of column 1. (If column 1 equal to 'source1', the dropdown values of column 2 will be the array source1, if it's equal 'source2', source of column 2 will be the array source2) :
Get the properties of the cell with getCellMeta(row,column)
Access the source and change it for your new array
Parameter row is the current row where you triggered the event afterChange, value is the value of column 1 for this row:
function setDropDownSource(row, value) {
var instance = this;
var cellPropertiesOption = instance.getCellMeta(row,1); // Column 1 is your 2nd column
if (value == 'source1')
cellPropertiesOption.source = source1;
else if (value == 'source2')
cellPropertiesOption.source = source2;
else
cellPropertiesOption.source = null;
}
This function is called in the afterChange event as follow :
$.each(changes, function (index, element) {
var rowIndex = element[0];
var columnIndex = element[1];
var newValue = element[3];
if (columnIndex == 0) { // Checking if the event has been triggered within the column SourceSelector
setDropDownSource.call(instance, rowIndex, newValue);
instance.render();
}
});
I also add an afterLoadData event to set the source for each rows of the 2nd column when loading the page. But I also wanted to empty the current value of a cell when the source is changed. So you will find an additional parameter for the function to set the condition if the cell needs to be empty or not when changing the source :
if (!init)
instance.setDataAtCell(row,1,"");
You can find the full working example in this JSFiddle.

JQGrid getRowData for all rows in certain order

I want to get all the rows of JQGrid in a javascript variable in a certain order.
I was able to get the data of all rows by :
var rowData = $("#gridId").jqGrid("getRowData");
But I want the rows to appear in the same order as that I entered in the grid.
I am trying to create a table and get its column details through the grid. So I require the order of the columns to remain the same. Any suggestions?
You can explicitly push the jqgrid rowdata to an array and then convert that to json string.
To do that you may use a function like the one given below to iterate through the jqgrid rows:(From Oleg's answer)
var gridData= {};
var $grid = jQuery("#gridId"), rows = $grid[0].rows, cRows = rows.length,
iRow, rowId, row, cellsOfRow;
for (iRow = 0; iRow < cRows; iRow++) {
row = rows[iRow];
if ($(row).hasClass("jqgrow")) {
cellsOfRow = row.cells;
// row represent the row with cellsOfRow.length cells.
// So one can use for loop with iCol between 0 and cellsOfRow.length
// cellsOfRow[iCol] represent the cell with the index iCol
// and $(cellsOfRow[iCol]).text() - the text of the cell
}
}
Inside the loop you can push the celldata to an array.
gridData['column_index1'] = $(cellsOfRow[0]).text();
gridData['column_index2'] = $(cellsOfRow[1]).text();
.............................................
Finally convert gridData to json string using
var result = JSON.stringify(gridData) ;

Google visualization DataTable: calculate totals

I'm searching a way to add a row of totals to a simple DataTable. This is my code:
// Create and populate the data table.
var dt = new google.visualization.DataTable();
dt.addColumn('string', 'Name');
dt.addColumn('number', 'Height');
dt.addRows([
['Tong Ning mu', 174],
['Huang Ang fa', 523],
['Teng nu', 86]
]);
var myTotal;
/* calculate total sum of column Height */
dt.addRow(['TOTAL', myTotal]);
// Create and draw the visualization.
visualization = new google.visualization.Table(document.getElementById('table'));
visualization.draw(dt, null);
How to calculate myTotal from dt DataTable?
Is it possible to make the last row(Totals) bold?
Is there any more elegant way to add totals to a table?
create the following function:
function getSum(data, column) {
var total = 0;
for (i = 0; i < data.getNumberOfRows(); i++)
total = total + data.getValue(i, column);
return total;
}
call it with your created google datatable, and column array index. In your case:
var total = getSum(dt,1);
Then, you can add that total into a new raw or what ever you want to do with it.
As #Danny's reply is the same solution as I would say for suming the column, I won't write it.
To set a cell property you dataTable.setProperty(columnIndex,rowIndex,'style','font-weight:bold;');
so in your case you'd write
dt.setProperty(0, 3, 'style','font-weight:bold;');
dt.setProperty(1, 3, 'style','font-weight:bold;');
Say you provide a bit bigger dataTable, it might be inconvenient to type this for all cells, you could use a for loop like (to make the whole last row bold):
var lastRow = dt.getNumberOfRows()-1
for (i=0, n=dt.getNumberOfColumns(); i < n; i++) {
dt.setProperty(i, lastRow, 'style', 'font-weight:bold;');
}
Sadly you're unable to set properties to a whole row/column (see the documentation about custom properties regarding this).

Javascript: sorting objects

I'm looking for some ideas of how to accomplish this as I am hitting a wall on it.
I have a table that displays data pulled from a MySQL db. The table goes in a sequence of a row of 13 cells with displayed data followed by a hidden row of one cell. The hidden row is toggled by clicking a link in cell index 1 of the previous row. Like so:
row 1 : click this cell to show row 2 : another cell : another cell : ad nauseum till we get to 13 :
row 2 which is hidden
row 3 : click this cell to show row 2 : another cell : another cell : ad nauseum till we get to 13 :
row 4 which is hidden
...
so using jquery I pulled all the rows, then set a test to determine if it was a displayed row or hidden row, if it was displayed then I put that row and the following one into an object and then placed that object into another object, like so:
//this function is for sorting the data in the table
$(".sort").click(function() {
//get what column we are sorting by
var sortBy = $(this).attr('sortBy');
//set the colnum to sort by
if (sortBy == "itemname") {
var sortCol = 1;
} else if (sortBy == "priority") {
var sortCol = 2;
} else if (sortBy == "livedate") {
var sortCol = 10;
} else if (sortBy == "status") {
var sortCol = 11;
} else if (sortBy == "designer") {
var sortCol = 12;
}
//get the table data
var tableData = getTableData("NO", "null", "YES", sortBy);
//get all the rows
var tableRowArray = $("#productTableBody tr");
//declare new table object
var tableObj = new Object;
var rowPackage = new Object;
//loop through tableRowArray and put rows into packages of two, the main row and the hidden row
for(var t=0; t<tableRowArray.length; t++) {
if($(tableRowArray[t]).children(":first").attr('class') == "colorCode") {
rowPackage[t] = $(tableRowArray[t]).children();
rowPackage[t+1] = $(tableRowArray[t+1]).children();
//dump rows into tableObj
tableObj[t] = rowPackage;
}
//clean out rowPackage
rowPackage = {};
}
var x=-2;
for(thisRow in tableObj) {
x = x+2;
var sortItem = $(tableObj[thisRow][x][sortCol]).html();
//ack! -->getting stumped here
}
});
I've also collected which column the user wants to sort by. I can then find the cell the user wants to sort by. I know I need to pull that info, put into an array and sort but I guess I am getting stumped on how to apply the sorted array back to my tableObj so I can rewrite the table body HTML...the reason I am getting stumped is that some of the data to be sorted will be identical, for example if sorting by designer the data could be this {"a", "b", "c", "c", "a", "a", ""a"}, which when sorted would be a, a, a, a, b, c, c, but since some are identical I can't go back and loop through the object and find the entry that matches the first item in my sorted array, 4 items will match it. So how do I determine which entry in the object matches up with the first a in the sorted list?
Thanks in advance.
That's a tough one, but I suppose there is hardly anything impossible in this life.
I would go like this (using Underscore library)
var packs = [];
// assuming you always have even number of tr's
$("#productTableBody tr:odd").each(function(i, tr){
packs.push( {main: tr, sub: tr.next()} );
// tr.next() will be :even, so it's not yet selected
// now detach rows from the table
// note the order - next() wont work otherwise
tr.next().remove();
tr.remove();
});
var sortedPacks = _(packs).sortBy(function(pack){
return $(pack.main).find('td:nth('+sortCol')').text();
});
// now in sortedPacks you have touples of rows sorted by "main" rows sortCol column
// and you would probably want to restore the table now
$.each(packs, function(i, pack){
$("#productTableBody").append(pack.main).append(pack.sub);
});
The code may not reflect your situation perfectly, but I suppose you should be able to get the main idea.
Not really to easy to get what you are asking for here, but this will at least enable you to get the data sorted.
Start by collecting your data into an array, eg data, each row can be represented by either an array or an object.
Now simply call
data.sort(function(a, b){
// select the two values from a and b depending on the column to sort by
a = a[colNr];
b = b[colNr];
return a == b ? 0 : a < b ? -1 : 1;
});
Now you can easily rebuild your table based on the sorted array.
If you during data-collection also added a reference to the row to the array/object, then you can now remove all rows from the table, loop over the data array, and add each node back to the table.

Categories