handsontable's subproject rulejs: how to get the calculated value of a formula cell? - handsontable

rulejs subproject of handsontable is great. But I can't find anything that emulates the "paste special" of spreadsheets. So, if I write
afterOnCellMouseDown: function(r, c) {
var x = hotdata[c['row']][c['col']];
document.getElementById("valorCelCorrente").innerHTML = x;}
I get the formula, not the calculated value that the cell is displaying. Same happens with a manual copy & paste.
A fiddle with example: https://jsfiddle.net/zota/j2a04w83/3/
Any clue? Thanks a lot
Julio

I had the same issue, but solved it with the help of this question.
Firstly you can use hot.plugin.helper.cellValue('CELL REF') to get the actual value, but when using getData() you're looking at the whole set. To solve this problem I basically iterated through the array replacing any formula cells with the value (I only needed columns up until 'K'):
var aCols = ['A','B','C','D','E','F','G','H','I','J','K'];
var data = hot.getData();
for (i = 0; i < data.length; i++){
for(j = 0; j < data[i].length; j++){
if(data[i][j].toString().indexOf('=') > -1){
data[i][j] = hot.plugin.helper.cellValue (aCols[j] + (i+1));
}
}
}

Related

For loop runs again after condition is met

I'm working on crating a function that adds data from numerous sheets in a Google Sheets document. The function creates production sheets that has a name and data slot as well as column titles for data that the function will paste into the sheet "Print". I am having an issue where a for loop seems to run an additional time even though the conditions are met as far as I can tell. Here is the code I have so far, its ugly but I'm just building this for myself.
function pasteToPrint(){
var ui = SpreadsheetApp.getUi()
var spreadsheet = SpreadsheetApp.getActive();
var sheetName;
var sheets = SpreadsheetApp.getActiveSpreadsheet().getSheets();
var lastCol;
var lastRow;
var a;
var x;
var y;
var z;
var array1 = [];
var array2 = [];
function getNextPage(){ // spreads subsequent data set to page break for printing
x = spreadsheet.getSheetByName("Print").getLastRow();
y = x/32;
y = Math.ceil(y);
z = 32*y;
return z;
}
for(var i = sheets.length-1; i > 4; i--){ // loops through the appropriate sheets and pushes to array1
lastCol = spreadsheet.getSheetByName(sheets[i].getName()).getLastColumn()+1;
lastRow = spreadsheet.getSheetByName(sheets[i].getName()).getLastRow()+1;
array1.push(spreadsheet.getSheetByName(sheets[i].getName()).getRange(1, 1, lastRow, lastCol).getValues());
}
for(var i = 0; i < array1.length; i++){
for(var j = 0; j < array1[i].length; j++){
// Looking for data that has a value grater than 0 at .slice(2,3)
if(array1[i][j].slice(2,3) > 0){ // Ref1
for(var k = 0; k < array1[i].length; k++){ // here I push that data to array2
if(array1[i][k].slice(2,3) > 0){ // ref 2
array2.push(array1[i][k]);
}
}
ui.alert(array2+" test 1"); // lets me know the content of array2
ui.alert(array2.length); // tells me the length just to be sure
for(var l = 0; l < array2.length; l++){ // decides where to paste the next data set
if(spreadsheet.getSheetByName("Print").getLastRow()>1){ // ref 3
a = getNextPage(); // returns the next 32nd line
}
else {
a = 1; // starts at row 1
}
// this next section is column formatting for the beginning of the production sheet
// ref 4
spreadsheet.getSheetByName("Print").getRange(a,1).setValue("Name:");
spreadsheet.getSheetByName("Print").getRange(a,3).setValue("Date:");
a++; // moves to the next row
spreadsheet.getSheetByName("Print").getRange(a,1).setValue("Product");
spreadsheet.getSheetByName("Print").getRange(a,2).setValue("Work Order");
spreadsheet.getSheetByName("Print").getRange(a,3).setValue("Planned Production");
spreadsheet.getSheetByName("Print").getRange(a,4).setValue("Product Produced");
spreadsheet.getSheetByName("Print").getRange(a,5).setValue("Steel Shortage");
spreadsheet.getSheetByName("Print").getRange(a,6).setValue("Notes");
a++ // moves to the next row
// ref 5
for(var m = 0; m < array2[l].length-1; m++){ // HERE IS THE PROBLEM LOOP
ui.alert(array2[m]+" test 2"); // I see this run an additional time after m = length
spreadsheet.getSheetByName("Print").getRange(a,1).setValue(array2[m][0]);
spreadsheet.getSheetByName("Print").getRange(a,2).setValue(array2[m][4]);
spreadsheet.getSheetByName("Print").getRange(a,3).setValue(array2[m][2]);
a++;
}
}
array2 = []; // array2 is emptied
break; // First if statement checking .slice(2,3) now has the function go to the next sheet
}
}
}
ui.alert("Function ended"); // just letting me know
};
imagine that there are numerous sheets in this document with data like the following except that there might be hundreds of rows after the column titles with different part numbers and so on
Material Req Planned Quantity MTs Planned Order
AI UPC300 1 1 86 12744851
The Plan Quantity column is what the .slice(2,3) is looking for. By default when I paste the original data into the sheets from my inventory system the value of Planned Quantity will be 0. After I have gone through the document and planed production, this means I have assigned a value to planned quantity greater than 0, I will run the function to paste the data to the print sheet. There could be hundred of items but I will only plan a portion of them, that's why this is handy. I can't share the full document I'm working with because it has sensitive data in it. If you create a google sheet with one sheet named print and a second sheet named whatever you want you can then paste the example data on rows 1 and 2 of the second sheet and you will see the error I get which is
TypeError: Cannot read property '0' of undefined (line 138, file "arrayTest")
You must also change for(var i = sheets.length-1; i > 4; i--) to for(var i = sheets.length-1; i > 1; i--), change the 4 to a 1. I have more code in my document but it is comprised of separate functions from this function.
I have added an image below that showcases how this would look before I utilize the function as well as how the Print sheet would look after the function has run. I had to screenshot this unfortunately so the data is condensed. Imagine that each section of data you see, green, blue, and white, are on their own sheets. For clarity the data in green would be contained in TestSheet1, the data in blue in TestSheet2, and the Print sheet would be totally blank before this function runs. Once I have entered my planned quantities in the Planned Quantity columns of TestSheet 1 and 2 I would then run the function. This would result in the data being pasted to the print page. I have added "ref" comments to the code to show where each step of the following explanation occurs. The function runs in this order: 1) The function will determine if a sheet has any values greater than zero in the Planned Quantity column, "ref 1". 2) The function would them loop through the sheet and push any row that met this criteria to array2, "ref 2". 3) The function will determine where to paste the data into the Print sheet based on data that may already by pated to the sheet, row 1, row 32, row 64, and so on, "ref 3". 4) the function will paste a header above the soon to be pasted data. This header include name, date, and column titles. 5) Once the header is placed the function will loop through array2 and paste is contents to the Print sheet, "ref 5". 6) the function will set array2 so that array2 = [] and will then repeat the process for the next sheet until all the sheets have been gone over and there is no more data to paste into Print, "ref 6".
The m loop is unnecessary. It's looping over current row(ls) columns. A mcve looks like this:
const array2d = [1, 2, 3].map(num => new Array(6).fill(num));//boilerplate to simulate array2
console.log({array2d});
for (var l = 0; l < array2d.length; l++) {
for (var m = 0; m < array2d[l].length - 1; m++) {
// HERE IS THE PROBLEM LOOP
// alert(array2d[m] + ' test 2'); // I see this run an additional time after m = length
console.log(array2d[m][0], array2d[m][2], array2d[m][4]);
}
}
Solution:
Remove the loop entirely.
a++; // moves to the next row
// for(var m = 0; m < array2[l].length-1; m++){ // HERE IS THE PROBLEM LOOP
// ui.alert(array2[m]+" test 2"); // I see this run an additional time after m = length
spreadsheet
.getSheetByName('Print')
.getRange(a, 1)
.setValue(array2[l][0]);
spreadsheet
.getSheetByName('Print')
.getRange(a, 2)
.setValue(array2[l][4]);
spreadsheet
.getSheetByName('Print')
.getRange(a, 3)
.setValue(array2[l][2]);
a++;
// }
}
Best practices:
Essential optimization

Nested For Loops Explanation Needed

Basically, in this program, I was instructed to create an array of random numbers and then sort them smallest to largest by bubble sorting with for loops. With a bunch of trial and error, my buddy and I were able to figure it out but I just took a look back at my code and honestly, it's very hard to comprehend.. I'm not too familiar with nested loops so if someone could explain how this method is working, that would be awesome. More specifically, what does the value j and i stand for.
public void sort() {
int val = 0;
for(int i = 0; i < myArray.length; i++) {
for(int j = 1; j < (myArray.length - i); j++) {
if(myArray[j-1] > myArray[j]) {
val = myArray[j-1];
myArray[j-1] = myArray[j];
myArray[j] = val;
}
}
}
}
Any answers are greatly appreciated, thanks guys/gals!
i and j are short with no inherent meaning other than to represent the index you are at in the array. The first for loop is so that the second loop and the sorting method are repeated for as many items are in the array. The second loop does the sorting.
if(myArray[j-1] > myArray[j]) { // Checks if the index `j` in the array is less than the one before it.
val = myArray[j-1]; // Temporarily stores the greater value.
myArray[j-1] = myArray[j]; // Swap the numbers.
myArray[j] = val; // Swap the numbers.
}

Delay code execution in VCL Forms Application

Need to animate a sorting algorithm, with source code line by line visualization.
INTRO:
For the begining, there is a FORM (see it in the picture attached). On top of that form is displayed a dinamicaly created array of Edit components, containing the array to sort.
A little below, on the right is placed a Memo component, containing the algorithm. At the left of each line of that algorithm, dinamicaly is placed a Label, that indicates the line number in algorithm.
The idea is to highlight line by colouring that label, where is the execution at the moment. Sorting starts when "Start" button is clicked. The action for it is following:
int n = 10;
bool swapped = true; hl(1);
int j = 0; hl(2);
int tmp; hl(3);
while (swapped) { hl(4);
swapped = false; hl(5);
j++; hl(6);
for (int i = 0; i < n - j; i++) { hl(7);
if (arr[i] > arr[i + 1]) { hl(8);
tmp = arr[i]; hl(9);
arr[i] = arr[i + 1]; hl(10);
arr[i + 1] = tmp; hl(11);
swapped = true; hl(12);
} hl(13);
} hl(14);
} hl(15);
The hl function must colour labels and pause execution by using Sleep() function
void TForm2::hl(int l)
{
for (int i = 0; i < 24; i++) {
Form2->lines[i]->Font->Color = clGray;
}
Form2->lines[l-1]->Font->Color = clRed;
Sleep(300);
}
PROBLEM:
Code execution is pausing (sleep function works properly), but the labels are still gray, with no visible changes, except the last one, when event finishes. The 15th line is red.
QUESTION:
Can anybody tell me, where I'm wrong, and how to do it right?
http://i.stack.imgur.com/crGyC.jpg
You need to allow the paint message to be processed in order to visually update the display. You can do that with either the Refresh or Update procedures:
Form2->Lines[l-1]->Font->Color = clGray;
Form2->Update(); // or Form2->Refresh();

OpenCV image pointer not working as expected

So I have to do some operations on part of an image. The operation is not relevant (i dont change this code at all), but the way i create the pointer changes the results i get. I dont understand why that happens.
Why does this code gets the result I want:
for(int row = 0; row < 70; ++row) {
for(int col = 48; col < 208; ++col) {
uchar* p = c.ptr(row+col);
*p = (1-circuloBinario.at<unsigned char>(row,col-48))*(*p) + circuloBinario.at<unsigned char>(row,col-48)*limite;
}
}
And this one doesnt?
for(int row = 0; row < 70; ++row) {
uchar* p = c.ptr(row+48);
for(int col = 48; col < 208; ++col) {
*p = (1-circuloBinario.at<unsigned char>(row,col-48))*(*p) + circuloBinario.at<unsigned char>(row,col-48)*limite;
p++;
}
}
By the way, I dont get any errors with the second code, the problem is that the result I get is not what I expect (it starts modifying the image from a row bigger than 0 and starts from column 0 instead of 48).
Thanks.
Mat::ptr returns a pointer to the specified matrix row.
See the documentation here: http://docs.opencv.org/modules/core/doc/basic_structures.html#mat-ptr
So neither c.ptr(row+col) nor c.ptr(row+48) make sense because you should only be passing a row index to the ptr function.
The way you use Mat::pt is apparently incorrect, as mentioned by M456.
If you want to modify the value of some elements of the matrix, why don't you use the following syntax?
c.at<element_type>(row, col) = new_value;

selenium xpath query

var value = selenium.GetXpathCount("//div[contains(#id,'spnPriceDetails')]");
int clickNo = 1;
for (var j = 1; j <= value; j++)
{
if (clickNo == j)
{
selenium.Click("//div[contains(#id,'spnPriceDetails')]");
}
clickNo = clickNo + 1;
}
I have 25 same links on one page I have Identify total number of links using Xpath Count. I Click on First Link But when i try to click on second and thirld link it click on first link every time instead of second and thirld
Your code isn't specifying a later link, it's doing the same search each time, retrieving all 25 that match "//div[contains(#id,'spnPriceDetails')]" and then clicking the first one in the resulting set of matches. You need to add the iterator variable into the search string, like so:
for (var j = 1; j <= value; j++)
{
selenium.Click("(//div[contains(#id,'spnPriceDetails')])[" + j + "]");
}
This way it will click through each value in the list of matches.
Note: I can't remember if xpath will start with 0 index or 1-index. It's supposed to be 1, but if it isn't you may need to start your loop at 0 instead.
I would try to use Position in the xpath expression.
I have created a fluent Xpath library that might be helpful:
The code would be something like:
for (int i = 1; i <= value; i++)
{
selenium.Click(XPathFinder.Find.Tag("div").With.Attribute("id").
Containing("spnPriceDetails").And.Position(i).ToXPathExpression());
}
Some more info on the XPath library can be found here:
http://www.unit-testing.net/CurrentArticle/How-To-Write-XPath-for-Selenium-Tests.html
I guess the plain xpath string way would be:
for (int i = 1; i <= value; i++)
{
selenium.Click(string.Format("//div[contains(#id,'spnPriceDetails') and position()={0}]",i)); }

Resources