How to read filtered rows in ClosedXML - closedxml

using (var workBook = new XLWorkbook(file)
I'm reading excel xlsx file with already defined filter.
Let's say that only rows with text 'abc' in column 2 are shown.
I cannot find any way to read this with ClosedXML. I can see that this filter exists by looking inside worksheet.AutoFilter but I cannot find a way to apply this. All the time I'm getting all rows from the worksheet. I want to get only those that are filtered and displayed when I open it in Excel.

Depending on version you use, you can do
var visibleRows = worksheet.RowsUsed(x => x.IsHidden == false);
Any rows that is hidden is filtered out.

Related

Google app-script .setValues() method is not writing to the Sheet

what i'm trying to do is to update data in a google sheet and then write that data back to the sheet.
1. I read the data from the spreadsheet
2. Go over the data if needed i add a row and add columns, i.e. i change the existing data.
3. now i need to write the data back in the spreadhsheet
the only thing that i can think of is that the range is bigger than the old range of column and rows and this might be causing the problem
//Reading the data initially:
var workingSheet = SpreadsheetApp.getActive().getSheetByName(storeSheetName);
var existingData = workingSheet.getDataRange().getValues(); //row 0 is column names
//do some manipulations on the data (add rows and columns)
// Writing the values :
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(storeSheetName).getRange(1,1,existingData.length,storeColumns.length).setValue(existingData);
when i try running the script in debug mode , it keeps getting stuck on the .setValues() row and will not proceed

Set row color with closedXML based on column value

I am trying to write Excel file from datatable with VB.NET. I am able to achieve few excel operations also. Now I want to colour a row based on cell value of a particular column (Col-4 for example). Here is my Excel file -
Here is my Excel file
I want to achieve like this -
Looking some guidance to achieve this.
I suggest you add conditional formatting. For example:
var workbook = new XLWorkbook();
var ws = workbook.AddWorksheet("Sheet1");
ws.FirstCell().SetValue(1)
.CellBelow().SetValue(1)
.CellBelow().SetValue(2)
.CellBelow().SetValue(3)
.CellBelow().SetValue(4);
ws.RangeUsed().AddConditionalFormat().WhenBetween(2, 3)
.Fill.SetBackgroundColor(XLColor.Red);
Reference: https://github.com/ClosedXML/ClosedXML/wiki/Conditional-Formatting

Append only unique rows

I am trying to read an external JSON API and write parsed values from it into google sheet. So each API call writes a new row into the sheet. The second requirement is to write the row only if it contains something else than already inserted rows - in other words append new row only if it is unique.
I've finished the first requirement. I've used JSON.parse and appendRow and it works with no problem.
Unfortunately, I cannot get thru the second requirement. I can not figure any construction nor find an example solution.
Does anybody have an advice how to append only unique rows from google apps script?
EDIT: My apologize for the above inexact post. Here are the details.
Below mentioned code is my solution for the first requirement:
function run() {
var data = UrlFetchApp.fetch("https://url/json-api").getContentText();
var json = JSON.parse(data);
var last = (json.last);
var credit = parseInt(json.credit);
var doc = SpreadsheetApp.openById("googleSheetID");
var list = doc.getSheets()[0];
list.appendRow([last, credit]);
}
So it simply append new row each time I run the script. Unfortunately, the returned JSON changes only from time to time. When I scheduled the script to run every 5 minutes it leads to many redundant rows.
However I don't want to run any kind of distinct after the redundant rows are written. I'd like to check if the new parsed data is unique and if so - write, otherwise nothing.
getLastRow's value and check whether it's equal to last/credit. Then appendRow, if needed.
Script Sample Snippet:
var lastRow=list.getRange(1,list.getLastRow(),1,2).getValues(); //[[prev.last,prev.credit]]
if(lastRow[0][0]!=last && lastRow[0][1]!=credit){
list.appendRow([last, credit]);
}

Copying values from Google sheet, add time stamp, prevent duplicates

I'm using Kimono to scrape a site that lists active development permits. For a one off data scrape it's fine, the problem is that there is no way of sorting new data. Every time Kimono scrapes it updates the entire array.
This is what the sheet currently looks like
https://docs.google.com/spreadsheets/d/1BH8ESAHQJrog6x8nRBOpgBN-nTN1_aDY7wr8W_YYet0/edit#gid=1865015934
The first sheet is automatically populated and overwritten by Kimono. It seems like the most logical way of making this work would be to copy the values to another sheet, adding a time stamp when this happens and then preventing duplicate values from being posted.
Following this thread is was able to muster this code
I've got the copying part down with the following:
function moveValuesOnly() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var source = ss.getRange('Building Permits!A1:D');
source.copyTo(ss.getRange('Sheet2!A1'), {contentsOnly: true});
source.clear();
}
What I am trying to figure out is how to prevent duplicates based on the URL value.
I know that it is right in front of me, but I'm drawing a blank on how to get this to work.
This Google documentation article on removing duplicates is very well written, so I won't duplicate it: https://developers.google.com/apps-script/articles/removing_duplicates
It has exactly what you need. Read the later part of the article where it talks about how to check duplicates not for the entire row, but specific columns in that row. Once you understand that, your problem is straightforward to solve. Just use 2 arrays, to hold the contents of the rows from the 2 sheets as in the example they've given. compare the first column value of the current row. if it matches, don't copy the row over.
note: this works only when you copy row-by-row into the target sheet, not the entire range as your'e doing right now. But that's unavoidable.

Changing data in a Google spreadsheet

I am changing a few cells of data in a Google spreadsheet. I would like to write back the data into the spreadsheet. The problem i have is that the sheet has say 5 columns, when i add new data into one of the cells i would like to backup the old data in the next free cell in that row. When i do this i am not able to write back the data. This is my code.
var sheet = SpreadsheetApp.openByUrl("URL");
var d = sheet.getSheetByName('Form Responses').getDataRange().getValues();
var head = sheet.getSheetByName('Form Responses').getRange(1,1,1,sheet.getLastColumn()).getValues()[0];
d[29][2] = "A";
d[29][3] = "B";
d[29][4] = "C";
d[29][5] = "D";
sheet.getSheetByName('Form Responses').getRange(1,1,d.length,d[0].length).setValues(d);
This is the error i get. Incorrect range width, was 6 but should be 5
I have also tried modifying the the write back statement as
sheet.getSheetByName('Form Responses').getRange(29,1,1,d[29].length).setValues(d[29]);
In this case i get Cannot convert Array to Object[][].
What is the correct way to write back the data. Preferably i would like to write back data of that particular row only, instead of the whole sheet data.
The issue here is that you modify only one "row" in the array so that in the end it is not "symetric" anymore (ie every rows don't have the same length) and that causes the error you get.
possible solutions :
There are probably more than one good way to avoid that error, you could create a second array with new data (same height) and join the arrays before writing back to the sheet or, as in the example below, add a cell (or many cells) to every row in the array in a loop before assigning them a new value. Depending on the size of the array one could be better and/or easier than the other to implement... here is a simplified example that should work :
for(var n=0;n<d.length;n++){
d[n].push('');
Logger.log('row '+n+' = '+d[n]+'\n');// see the result
}
EDIT following comment :
OR you can write a single row if you change only one, just change the code to
sheet.getSheetByName('Form Responses').getRange(29,1,1,d[29].length).setValues([d[29]])
which is not far from what you tried but you were simply missing the pair of brackets to get a 2D array as required by setValues()