Google-charts remove column with multiple checkboxes - javascript

languages: jQuery, javascript
Code below: Working well.
(...)
var check_box_values = $('#myForm [type="checkbox"]:not(:checked)').map(function ()
{
return this.value;
}).get();
Code below: Working well.
function f(check_box_values)
{
(...)
var obj = jQuery.parseJSON(jsonData);
var data = google.visualization.arrayToDataTable(obj);
Code below: for cycle goes fine but if statement never starts
for (var i = 1; i < data.getNumberOfColumns()-1; i++)
{
if ($.inArray(i, check_box_values) > -1)
{
data.removeColumn(i);
}
}
Html code: Working well.
What am I doing wrong?
note: the check_box_values array is populated.
edit: (eg.)
getNumberOfColumns: 6
check_box_values array: [1,3,5]

I see a problem in your code. Once data.removeColumn is called, the column index will be reset, and the result from getNumberOfColumns() will be different than what you expect. In the other words, this function is not designed to be called inside a loop.
Here is an example. Suppose you have five columns with the columIndex ranging from 0-4. You like to remove the 3rd (columnIndex: 2) and the 5th (columnIndex: 4) column. Once your code has been executed the first time, i.e., removeColumn(2), the column index will get shifted and the getNumberOfColumns() will become 4. If you call removeColumn(4), it will cause run-time error because the index is not pointing to any column. You should call removeColumn(3) instead.

Related

Finding an empty cell in a column using google sheet script

I am trying to find an empty cell in a specific column in google sheets. I am familiar with getLastRow(), but it returns the last row in whole sheet. I want to get the first empty cell in a specific column. So, I used a for loop and if. But I don't know why it is not working. The problem is that for loop does not return anything.
I am getting 10 rows of the column H (position 8) in the sheet test (line2). first 5 rows already have content. Data will be added to this cell later using another code. so, I want to be able to find the first empty cell in this column to be able to put the new data.
var sheettest = SpreadsheetApp.getActive().getSheetByName("test");
var columntest = sheettest.getRange(4, 8, 10).getValues();
for(var i=0; columntest[i]=="" ; i++){
if (columntest[i] ==""){
var notationofemptycell = sheettest.getRange(i,8).getA1Notation();
return notationofemptycell
}
}
As I said, I want to find the first empty cell in that column. I defined the for loop to go on as long as the cell is not empty. then if the cell is empty, it should return the A1 notation of that cell.
It seems the for loop does go on until it find the empty cell, because I get no definition for the var "notationofemptycell" in debugging.
This may be faster:
function getFirstEmptyCellIn_A_Column() {
var rng,sh,values,x;
/* Ive tested the code for speed using many different ways to do this and using array.some
is the fastest way - when array.some finds the first true statement it stops iterating -
*/
sh = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('test');
rng = sh.getRange('A:A');//This is the fastest - Its faster than getting the last row and
//getting a specific range that goes only to the last row
values = rng.getValues(); // get all the data in the column - This is a 2D array
x = 0;
values.some(function(ca,i){
//Logger.log(i)
//Logger.log(ca[0])
x = i;//Set the value every time - its faster than first testing for a reason to set the value
return ca[0] == "";//The first time that this is true it stops looping
});
Logger.log('x: ' + x)//x is the index of the value in the array - which is one less than
//the row number
return x + 1;
}
You need to loop through the length of columntest. Try this:
function myFunction() {
var sheettest = SpreadsheetApp.getActive().getSheetByName("test");
var lr=sheettest.getLastRow()
var columntest = sheettest.getRange(4, 8, lr).getValues();
for(var i=0; i<columntest.length ; i++){
if (columntest[i] ==""){
var notationofemptycell = sheettest.getActiveCell().getA1Notation();
Logger.log( notationofemptycell)
break;//stop when first blank cell on column H os found.
}
}
}

Javascript Highcharts: series datalabel formatter function to loop data not formatting all data form the array

I'm running into an issue where the formatter method is not taking in all the data from the array. For example:
var test = [1234, 4567, 1564, 7899];
chartData.plotOptions.series.datalabels.formatter = function () {
for (var i = 0; i < test.length; i++) {
// formatNumber() is a dummy method in this example
return formatNumber(test[i]);
}
};
After the loop, the datalabel only shows the first index data on each segment of bar chart.
The result returns the first index only. I'm not sure why it's not looping through the whole array. Can someone please give me some assistance?
Your code will return after the first iteration of the for loop, which is why you only see the first index.
That said, the formatter is a callback that gets applied to each data point, so you shouldn't need to loop over your test values. You should try something like:
chartData.plotOptions.series.datalabels.formatter = function() {
return formatNumber(this.y);
}
Refer to the formatter documentation for available data to use.

Passing array of objects to a js function

i am trying for the first time to implement OOP in javascript and i got stuck on a recursive function when i try to send an array of objects to this function. So, i have the "Pitic" class (pitic means midget in romanian) with some propreties:
function Pitic(piticID) {
this.id = piticID;
this.inaltime = null;
this.greutate = null;
this.genereazaGreutate();
this.genereazaInaltime();
}
I'm now generating some midgets and storing them in the public piticiCollection Array variable. The "genereazaGreutate" and "genereazaInaltime" are function to generate random values for the inaltime and greutate values.
var pitic = new Pitic(idPitic);
piticiCollection.push(pitic);
The problem appears when i try to send the array of midgets to a function because all i get is only the first item of the array.
So, before i call the function, i have piticiCollection array with 4 objects:
midgets are safe and sound http://img443.imageshack.us/img443/484/yr4f.png
And as soon as i call the function with the piticiCollection as a parameter i loose 3 midgets! :(
most of the midgets are gone http://img201.imageshack.us/img201/5808/7od5.png
p.s. please excuse me for my bad english..
[EDIT]
Here is a fiddle of my full code: http://jsfiddle.net/WT7Ud/ I call the function on line 56 and as soon as the debugger hits line 60 i loose array items.
I have solved my problem by creating a copy of the array before using it in the function. Strange :(
function determinaPerechi(somePitici) {
var piticDeComparat, colectieDePiticiCopy;
colectieDePiticiCopy = somePitici;
for (var i = 1; i < colectieDePiticiCopy.length; i++) {
var piticDeComparat2 = null;
piticDeComparat = colectieDePiticiCopy[0];
piticDeComparat2 = colectieDePiticiCopy[i];
if (piticDeComparat.inaltime < piticDeComparat2.inaltime) {
//Perechea poate fi prietena
}
}
//colectieDePiticiCopy.splice(0, 1);
if (colectieDePiticiCopy.length == 0) {
//alert("finish");
return;
}
determinaPerechi(colectieDePiticiCopy);
//test(ttt);
}
Your determinaPerechiPosibile is modifying the original array on this line:
colectieDePitici.splice(1, colectieDePitici.length);
In particular, it is removing all but the first element. You probably should be using slice to non-destructively extract the part of the array you want to recurse on.
As Ted Hopp mentioned, the problem appears to be the line
colectieDePitici.splice(1, colectieDePitici.length);
in combination with this line:
determinaPerechiPosibile(colectieDePiticiCopy);
If those two lines are commented out, the array maintains its original length.

Javascript sort string or number

EDIT: Pete provided a really good solution that works when the fields contain numbers, however I need to be able to sort strings too - any ideas?
I'm trying to write a javascript sorting algorithm that will sort a table based on the column clicked - I know this is semi-reinventing the wheel but the design is too complex for me to try and insert some other plugin etc.
Some columns are text, some columns are numbers.
Clicking a column calls: sort(X,Y). X is the column number so we know which cells to compare for the sort. Y is the mode, i.e. ascending or descending.
The code for the sort function is:
function sort(field, mode) {
var tabrows = 0;
$(".data tr").each(function() { if($(this).hasClass("hdr")) { } else {tabrows++;} });
var swapped;
do {
swapped = false;
for (var i=0;i< tabrows; i++) {
var j = i + 3;
var k = i + 4;
var row1 = $(".data tr:nth-child("+j+")");
var row2 = $(".data tr:nth-child("+k+")");
var field1 = row1.find("td:eq("+field+")").text();
var field2 = row2.find("td:eq("+field+")").text();
if(shouldswap(field1, field2, mode)) {
swaprows(row1, row2);
swapped = true;
}
}
} while (swapped);
}
The shouldswap function is as follows:
function shouldswap(field1, field2,mode) {
if(field1 > field2) {
if(mode==1) {
return true;
} else {
return false;
}
}
return false;
}
Code for swaprows function:
function swaprows(row1, row2) {
row2.insertBefore(row1);
}
Can anyone see why this would cause the browser to freeze/lockup. I've been working on this for quite a while so I think a fresh pair of eyes may point out something silly! Any help is appreciated :)
The problem might be that you're calling the jQuery constructor a bunch of times and doing heavy operations on it (e.g. using .find() with complex selectors). Therefore, your function is just slow and that's probably the issue.
The good news is that JavaScript has a native implementation of QuickSort (a very fast sorting function) that will probably take care of your needs. When combined with a reduction in expensive calls, your code should end up being enormously more efficient. I'd change your code to look like this:
var sortByField = function(field, mode) {
var numExp = /^-?\d*\.?\d+$/;
var $rows = $(".data tr:not(.hdr)"), $table = $(".data");
$rows.each(function () {
this.fieldVal = $(this).find("td:eq("+field+")").text();
if(numExp.test(this.fieldVal)) { //if field is numeric, convert it to a number
this.fieldVal = +this.fieldVal;
}
}).sort(function (a, b) {
if (mode === 1) {
return (a.fieldVal > b.fieldVal) ? -1 : 1;
}
return (a.fieldVal < b.fieldVal) ? -1 : 1;
}).detach().each(function () {
$(this).appendTo($table);
});
};
This won't work well with multiple tables on one page (because it assumes everything is on the same table). So if you want to do that, you should pass in the table or table selector as a parameter. But that's an easy fix to make. You can see my solution in action here:
http://jsfiddle.net/r8wtK/ (updated)
It should be far more efficient than your code and should reduce "freezing" by quite a bit (ore even entirely).
UPDATE:
The OP noted that some fields may contain strings. Doing a string comparison on numbers is bad because it returns a lexicographical ordering (e.g. "10" < "2"). So I added a test to see if the data appear to be numeric before doing the sort.
Could it be that you're adding 3 and 4 to i in order to get your row indices? So when i gets to (tabrows-1), it appears that it will be trying to access rows with index of (tabrows+2) and (tabrows+3). If I understand your logic correctly, these are out of bounds, so row1, row2, field1 and field2 will be empty. Therefore, if you're in mode==1, I think this will make it so that your algorithm attempts to swap these two non-existent rows and keeps comparing for infinity. Does this make sense, or am I misunderstanding your logic?
If that's the case, I think you just need to change your for loop to:
for (var i=0;i< tabrows-4; i++) {
// your code
}
What is the purpose of adding 3 to j and 4 to k anyway? Do you have 3 rows of data at the top that you don't want to compare?

Array iteration issue in Javascript

I´m trying to make a function that reads elements from an array and distributes its values to <tr> tags of a table.
So I wrote this code:
(function () {
"use strict";
var selectQG = {
distributeCat : function (tablerow, categories) {
var tr = $(tablerow), tri = 0;
tr.each(function () {
if (tri > 2) {
for (var i = 0; i<categories.length; i++) {
this.setAttribute('categoria',categories[i]);
}
}
tri++;
});
}
}
var categories = ['1,2','3,4','5,6','7,8','9,10','11,12'];
selectQG.distributeCat('table tr', categories);
} () );
Check this fiddle to see the html code and the function working: http://jsfiddle.net/5kqEf/2/ )
The loop is being executed 6 times and I can´t figure out why. I´m still a novice at programming, so I´m in need of some help to know what I´m doing wrong. Any help would be very appreciated.
EDIT: The ideia is that every <tr> get the array value. It is supposed to happen starting from the 3rd <tr>, that´s why I put that "if" conditional. So, the first <tr> get "categories[1]", the second <tr> get "categories[2]" and so on.
The outer loop is executed 9 times, since you have 9 table tr elements. The .each will loop over every tr element, which happen to be 9 elements. See http://jsfiddle.net/5kqEf/4/
The inner for loop loops over 6 elements (the array var categories = ['1,2','3,4','5,6','7,8','9,10','11,12'];), so that makes sense...
What is your exact question?
If you want to pick a categorie based on index (and startover if there are more tr elements than categories), you might want to replace this:
for (var i = 0; i<categories.length; i++) {
this.setAttribute('categoria',categories[i]);
}
with this
var index = tri % categories.length;
this.setAttribute('categoria',categories[index]);
See https://developer.mozilla.org/en/JavaScript/Reference/Operators/Arithmetic_Operators for use of the modulus operator.

Categories