How to write into a particular cell using xlsx npm package - npm

I have to write a value to a particular cell (say the D4 cell) in my xlsm file. I can see the option of
XLSX.writeFile(workbook, 'out.xlsx');
in the XLSX package documentation (writing functions)
But I am not seeing anything to write a value to a particular cell (where should the values which needs to be written passed?). Or, it is not as clear as the example provided to read a particular cell value.
Would be glad if someone could provide me a simple example of snippet.
This is how I read a particular cell value:
if(typeof require !== 'undefined') XLSX = require('C:\\Program Files\\nodejs\\node_modules\\npm\\node_modules\\xlsx');
var workbook = XLSX.readFile('xlsm');
var first_sheet_name = workbook.SheetNames[0];
var address_of_cell = 'D5';
var worksheet = workbook.Sheets[first_sheet_name];
var desired_cell = worksheet[address_of_cell];
desired_value = (desired_cell ? desired_cell.v : undefined);
console.log('Cell Value is: '+ desired_value);

So to write to a specific cell in a defined sheet - lets say first sheet, you can do:
const XLSX = require('xlsx');
// read from a XLS file
let workbook = XLSX.readFile('test.xls');
// get first sheet
let first_sheet_name = workbook.SheetNames[0];
let worksheet = workbook.Sheets[first_sheet_name];
// read value in D4
let cell = worksheet['D4'].v;
console.log(cell)
// modify value in D4
worksheet['D4'].v = 'NEW VALUE from NODE';
// modify value if D4 is undefined / does not exists
XLSX.utils.sheet_add_aoa(worksheet, [['NEW VALUE from NODE']], {origin: 'D4'});
// write to new file
// formatting from OLD file will be lost!
XLSX.writeFile(workbook, 'test2.xls');
Hope that helps

Modify value in D4
worksheet['D4'].v = 'NEW VALUE from NODE';
This will work only if the cell already defined in the file, but sometimes you will want to write to a new undefined cell.
so, the solution I found for that is:
modify value in new cell- D4
XLSX.utils.sheet_add_aoa(worksheet, [['NEW VALUE from NODE']], {origin: 'D4'});

Related

Appscript setformula parsing error. but seems working

I'm trying to set formula in google spreadsheet cell using this code
function SetFormuleSettimana(row) {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var Settimane = ss.getSheetByName("Settimane");
var cell = Settimane.getRange("I" + row);
cell.setFormulaR1C1('ArrayFormula(Indice(Gruppi!A:G;Confronta(1;(G' + row + '=Gruppi!A:A)*(H' + row + '=Gruppi!B:B);0);5))');
}
The cell seems correctly filled with the formuala =ArrayFormula(Indice(Gruppi!A:G;Confronta(1;(G2=Gruppi!A:A)*(H2=Gruppi!B:B);0);5))
but I get a "Parsing Error", analyzing the formula in spreadsheet the help give correct value.
There is a problem with setting formulas with Apps Script in a language other than English.
To set your formulas programmatically, for the meantime you need to use the corresponding English names of the formulas.

Workbook cell style in POI/NPOI doesn't work properly with multiple styles in workbook

I'm running into strange problem with .Net version of POI library for Excel Spreadsheets. I'm rewriting from text files to Excel 97-2003 documents and I'm like to add some formatting programmatically depend on some values gather at the begging of the program.
At the beginning, in the same method where I was creating a new cell from given value I was creating also a new Workbook CellStyle which was wrong, because I was running out of the styles very quickly (or I was just thought it was the cause of the problem).
Constructor of the class responsible for Excel Workbook:
public OldExcelWriter(TextWriter logger) : base(logger)
{
_workbook = new HSSFWorkbook();
_sheetData = _workbook.CreateSheet("sheet1");
_creationHelper = _workbook.GetCreationHelper();
}
Method that is calling all the chains of operations:
public void Write(string path, Data data)
{
FillSpreadSheetWithData(data, _sheetData);
SaveSpreadSheet(_workbook, path);
}
Long story short, in FillSpreadSheetWithData I have method for creating a row inside which I'm have a loop for each cell, so basically I'm iterating thru every column, passing IRow references to a row, column value, index and formatting information like this:
for (int j = 0; j < column.Count; j++)
{
CreateCell(row, column[j], j, data.Formatting[j]);
}
and while creating a new styles (for first shot I was trying to pass some date time values) I had situation like this in my rewrited Excel: screenshot of excel workbook
So formatting was passed correctly (also Horizontal Aligment etc.) but it get ugly after 15th row (always the same amount).
DateTime dataCell = DateTime.MaxValue;
var cell = row.CreateCell(columnIndex);
_cellStyle = _workbook.CreateCellStyle();
switch (format.Type)
{
case DataType.Date:
_cellStyle.DataFormat = _creationHelper.CreateDataFormat().GetFormat("m/dd/yyyy");
if (value.Replace("\n", "") != string.Empty)
{
dataCell = DateTime.ParseExact(value.Replace("\n", ""), "m/dd/yyyy",
System.Globalization.CultureInfo.InvariantCulture);
}
break;
}
switch (format.HorizontalAlignment)
{
case Enums.HorizontalAlignment.Left:
_cellStyle.Alignment = HorizontalAlignment.LEFT;
break;
case Enums.HorizontalAlignment.Center:
_cellStyle.Alignment = HorizontalAlignment.CENTER;
break;
}
if (dataCell != DateTime.MaxValue)
{
cell.CellStyle = _cellStyle;
cell.SetCellValue(dataCell);
dataCell = DateTime.MaxValue;
}
else
{
cell.CellStyle = _cellStyle;
cell.SetCellValue(value);
}
(It's not the cleanest code but I will don refactor after getting this work).
After running into this issue I thought that maybe I will create _cellStyle variable in the constructor and only change it's value depends on the case, because it's assigned to the new cell anyway and I see while debugging that object values are correct.
But after creating everything, it won't get any better. Styles was override by the last value of the style, and dates are spoiled also, but later: screnshoot of excel workbook after creating one instance of cell style
I'm running out of ideas, maybe I should create every combination of the cell styles (I'm using only few data formats and alignments) but before I will do that (because I'm running out of easy options right now) I wonder what you guys think that should be done here.
cell format is set to custom with date type
I am using this code to create my custom style and format. Its for XSSF Format of excel sheet. but it will work for HSSF format with some modification.
XSSFFont defaultFont = (XSSFFont)workbook.CreateFont();
defaultFont.FontHeightInPoints = (short)10;
defaultFont.FontName = "Arial";
defaultFont.Color = IndexedColors.Black.Index;
defaultFont.IsBold = false;
defaultFont.IsItalic = false;
XSSFCellStyle dateCellStyle = (XSSFCellStyle)workbook.CreateCellStyle();
XSSFDataFormat dateDataFormat = (XSSFDataFormat)workbook.CreateDataFormat();
dateCellStyle.SetDataFormat(dateDataFormat.GetFormat("m/d/yy h:mm")); //Replace format by m/dd/yyyy. try similar approach for phone number etc.
dateCellStyle.FillBackgroundColor = IndexedColors.LightYellow.Index;
//dateCellStyle.FillPattern = FillPattern.NoFill;
dateCellStyle.FillForegroundColor = IndexedColors.LightTurquoise.Index;
dateCellStyle.FillPattern = FillPattern.SolidForeground;
dateCellStyle.Alignment = HorizontalAlignment.Left;
dateCellStyle.VerticalAlignment = VerticalAlignment.Top;
dateCellStyle.BorderBottom = BorderStyle.Thin;
dateCellStyle.BorderTop = BorderStyle.Thin;
dateCellStyle.BorderLeft = BorderStyle.Thin;
dateCellStyle.BorderRight = BorderStyle.Thin;
dateCellStyle.SetFont(defaultFont);
//Apply your style to column
_sheetData.SetDefaultColumnStyle(columnIndex, dateCellStyle);
// Or you can also apply style cell wise like
var row = _sheetData.CreateRow(0);
for (int cellIndex = 0;cellIndex < TotalHeaderCount;cellIndex++)
{
row.Cells[cellIndex].CellStyle = dateCellStyle;
}

Incrementing a value saved in Google Sheets Cache Service

I'm trying to store a value using google cache services but it doesn't seem to increment like I want it to. Here's the code -
//Starts a new instance of cache
var cache = CacheService.getScriptCache();
//Puts the value 2 into foo key of Cache
cache.put('foo', 2);
//Grabs that value
var startMessageRow = cache.get('foo');
//stuff for an email I'm sending using this cached value
var messageDataRange = sheet.getRange(startMessageRow, 2)
var message = messageDataRange.getValues();
//Here's where I'm trying to increment it, but the value is staying at 2
cache.put('foo','startMessageRow'+1);
That last line of code is where I'm trying to increment the value by one each time this script runs, however the value is just stuck at two no matter what I try.
I found an easier way to do this. I just put a counter in a random cell and then I just add one to that value every time my script runs. Way easier than using the cache services!
var cellRange = s1.getRange("W726"); //set this string to be the corresponding cell for daily counter
var cell = cellRange.getValues(); //grabs the value from that cell
var startMessageRow = cell; //sets StartMessage Row to be equal to the value of counter
startMessageRow = parseInt(startMessageRow);//ints it
cell = parseInt(cell); //ints it
cell+=1; //increments
cell = cell+""; // strings it
cellRange.setValue(cell); // puts the new value in

EPPLUS how to know the format of the Worksheet cell

I am using EPPlus to read excel sheets and load the data into datatable to perform further operations and then save back the modified data to the excel file.
The below code checks if the cell value is a float value then it converts the float value to datetime.
The code works fine when the cell value is a date eg: Invoice Date = 42009 , but it converts the not a date value like eg : amount = 10 to a date.
Is there any way in EPPlus library from which i can determine the format of the cell (i.e General/date/number etc) ?
float floatValue;
if (float.TryParse(Convert.ToString(oSheet.Cells[i, j].Value), out floatValue)
&& Convert.ToString(oSheet.Cells[i, j].Style.Numberformat.Format).Contains("[$-409]d\\-mmm\\-yy;#"))
{
dr[j - 1] = String.Format("{0:d-MMM-yy}", DateTime.FromOADate(floatValue));
}
else
{
DateTime date;
if (DateTime.TryParse(Convert.ToString(oSheet.Cells[i, j].Value), out date))
{
dr[j - 1] = String.Format("{0:d-MMM-yy}", date);
}
else
{
dr[j - 1] = Convert.ToString(oSheet.Cells[i, j].Value).Trim();
}
}
The short answer is if the data in Excel is formatted as a "proper" date field (its format is set to Date and it does not have the triangle in the cell corner) EPPlus will determine that and automatically convert it to a date in the cell store.
Excel stores this information in the XLSX xml files, e.g. sheet1.xml and styles.xml, which you can see by changing the file extension to .ZIP and opening as a compressed folder. So EPPlus will read XML flags and convert the field values to DateTime automatically. If you want to see its gory detail download the EPPlus source code and look at the function private void SetValueFromXml(XmlTextReader xr, string type, int styleID, int row, int col) in the ExcelWorksheet class.
I created a sheet, added a date value, and copy pasted the value to cell B2 but then set the format to number. I then copied B2 to B3 but made the value in B3 a string by putting an ' in front of the value. Like this:
and when I run this unit test everything passes:
[TestMethod]
public void Date_Number_Test()
{
//http://stackoverflow.com/questions/28591763/epplus-how-to-know-the-format-of-the-worksheet-cell
var existingFile = new FileInfo(#"c:\temp\datetest.xlsx");
using (var package2 = new ExcelPackage(existingFile))
{
var ws = package2.Workbook.Worksheets["Sheet1"];
var cell = ws.Cells["B1"];
Assert.IsTrue(cell.Value is DateTime);
cell = ws.Cells["B2"];
Assert.IsTrue(cell.Value is double);
cell = ws.Cells["B3"];
Assert.IsTrue(cell.Value is string);
}
}
But if you are dealing with a sheet with formatting outside your control then I think your approach is correct in that you will have to determine what the "intent" of the numbers are rather then being able to rely on EPPlus (really excel) is reporting them as.
if you want to know current cell format, why dont you use ExcelNumberFormat class?
var style=oSheet.Cells[i, j].style;
string format=style.Numberformat.Format;
This will give you current cell format, i.e, "YYYY-MM-dddd" , "%#.##", and so on.

EPPLUS - Get Name Of Cell//Range

I know it is possible to give a cell a name, as answered in the following question:
EPPLUS - Rename Cell
How can you see if a given cell/range has a name and retrieve that name?
There is a property i.e. IsName that can determine the range has a name or not. But it seems not to work properly. I suppose you to query the named cells collection i.e. sheet.Names or book.Names (they contains all the names in the sheet or the book). Then compare FullAddressAbsolute to the given cell to get the named cell you want.
var cell = sheet.Cells["C1"]; // cell you wanna find the name
ExcelNamedRange namedCell = null;
foreach (var item in book.Names)
{
if (item.FullAddressAbsolute.Equals(cell.FullAddressAbsolute))
{
namedCell = item;
break; // if you don't wanna find all
}
}
// if (namedCell == null) --> NOT FOUND
// else
// namedCell.Name : contains the name you wanna retrieve
LINQ can also be used instead of the loop:
namedCell = book.Names.Where(item => item.FullAddressAbsolute.Equals(cell.FullAddressAbsolute)).FirstOrDefault();