Script for Detecting Table Header Presence in Office Fails to Identify Absence of Header

Currently, I am developing a macro in Office Scripts for Excel that has several requirements:

  • Verify the existence of a column header in a specified table
  • If the column does not exist, add it and set the desired header
  • Write values to that newly added column

Unfortunately, the validation process for checking the non-existence of the column header seems to be ineffective. The code continues execution even when the header is missing, leading to a crash when trying to write to a non-existent variable.

I previously sought help on excelForum but did not receive any responses. Should I provide a link to my previous post?

I expected that:

let columnScore = table.getColumn("Score");
would return a column object and that: if (!columnScore) { ... }
should return TRUE and execute the if statement if the column object is not found.

According to the Office Scripts Documentation, the getColumn() method should return 'undefined' if a column is not found. Despite testing various conditions for an undefined variable, all have returned false.

What would be the most effective method to validate the presence of a table header?

I came across a discussion on optional chaining vs non-null assertions, but I am unsure how to apply it. Optional chaining appears to avoid execution if there is an undefined value, whereas I want it to execute if there is an undefined.

Below is a snippet of the relevant code:

function QAcolorTable(table: ExcelScript.Table){
  console.log("table: " + table.getName());
  
  //find or create column to for score formula
  let columnScore = table.getColumn("Score");
  console.log('null '+ (columnScore==null));
  console.log('type of ' + (typeof columnScore));
  console.log("undefined " + (columnScore==undefined));
  console.log("not " + !columnScore);
  console.log("void2 " + (columnScore == void 0));
  console.log("void3 " + (columnScore === void 0));
  if (!columnScore) {
    console.log("adding 'Score'");
    table.addColumn(-1, null, "Score");
    columnScore = table.getColumn("Score");
  }
}

And here is the complete code: Please note that the script: -searches for sheets with names containing "QA Checklist", -in those sheets, searches for a Table named "QAChecklist"

function main(workbook: ExcelScript.Workbook) {
  let sheets = workbook.getWorksheets();
  sheets.forEach(sheet => {
    let sheetName = sheet.getName();
    if(sheetName.search("QA Checklist") > -1){
      QA_color_Sheet(sheet);
    }
  });
}

function QA_color_Sheet(sheet : ExcelScript.Worksheet){
  console.log("sheet: " + sheet.getName() );
  let tables = sheet.getTables();
  tables.forEach(table => {
    let tableName = table.getName();
    if(tableName.search("QAChecklist") > -1) {
      QAcolorTable(table);
    }
  });
}

function QAcolorTable(table: ExcelScript.Table){
  console.log("table: " + table.getName());
  
  const scoreFormula = "=IF( [@[Consultant Checked]]=\"N/A\",NA(),SWITCH([@[Get Colour]],38, 1, 36, 0.5, 35, 0, \"#C6EFCE\", 0, \"#FFEB9C\", 0.5, \"#FFC7CE\", 1, 1))";
  let headers = table.getHeaderRowRange();

  //get the column object to read colours from Exit if not found.
  let columnRead = table.getColumn("Initial Reviewer Comments");
  if (columnRead === void 0) { columnRead = table.getColumn("Reviewer Comments"); }
  if (columnRead === void 0) {
    console.log("column [Initial Reviewer Comments]||[Initial Reviewer Comments] not found in " + table.getName());
    return;
  }
  let rngRead = columnRead.getRangeBetweenHeaderAndTotal();

  //find or create colum to write RGB color to. 
  let columnWrite = table.getColumn("Get Colour");
  if (columnWrite === void 0){
    console.log("Adding 'Get Colour'");
    table.addColumn(-1, null, "Get Colour");
    columnWrite = table.getColumn("Get Colour");
  }
  let rngWrite = columnWrite.getRangeBetweenHeaderAndTotal();

  //find or create column to for score formula
  let columnScore = table.getColumn("Score");
  console.log('null '+ (columnScore==null));
  console.log('type of ' + (typeof columnScore));
  console.log("undefined " + (columnScore==undefined));
  console.log("not " + !columnScore);
  console.log("void2 " + (columnScore == void 0)); 
  console.log("void3 " + (columnScore === void 0));
  if (columnScore === void 0) {
    console.log("adding 'Score'");
    table.addColumn(-1, null, "Score");
    columnScore = table.getColumn("Score");
  }
  console.log(scoreFormula)
  columnScore.getRangeBetweenHeaderAndTotal().getCell(0,0).setFormula(scoreFormula);

  let rows = table.getRowCount();
  //write colour values to the write cells
  for (let rw = 0; rw < rows; rw++) {
    let cellColorRead = rngRead.getCell(rw, 0);
    let cellWrite = rngWrite.getCell(rw, 0);
    cellWrite.setValue(cellColorRead.getFormat().getFill().getColor());
  }
}

Answer №1

Your code for validating a column in a table seems to be correct. Consider simplifying the test case to make debugging easier.

function main(workbook: ExcelScript.Workbook) {
  let selectSheet = workbook.getActiveWorksheet();
  let selectTab = selectSheet.getTables()[0];
  let scoreCol = QAcolorTable(selectTab);
  scoreCol.getRangeBetweenHeaderAndTotal().getRow(0).setValue('Done');
}

function QAcolorTable(table: ExcelScript.Table) {
  console.log("table: " + table.getName());
  let columnScore = table.getColumn("Score");
  if (!columnScore) {
    console.log("adding 'Score'");
    table.addColumn(-1, null, "Score");
    columnScore = table.getColumn("Score");
  }
  return columnScore;
}

Console Output

table: tabDemo
adding 'Score'

https://i.sstatic.net/LZCxF.png


In Office Script, you can catch undefined as shown below.

function main(workbook: ExcelScript.Workbook) {
  let selectSheet = workbook.getActiveWorksheet();
  let selectTab = selectSheet.getTables()[0];
  let scoreCol = selectTab.getColumn("Score");
  console.log(typeof(scoreCol) === 'undefined');
}

While many use if (!columnScore) for validation, remember that it also catches null/0, not just undefined. See the table below for how the if condition evaluates different values.

function main(workbook: ExcelScript.Workbook) {
  let selectSheet = workbook.getActiveWorksheet();
  let selectTab = selectSheet.getTables()[0];
  let colS = selectTab.getColumn("NonExistCol"); // colS is undefined
  console.log("== undefined ==");
  console.log("null " + (colS === null));
  console.log("typeof " + ((typeof colS) === "undefined"));
  console.log("=undefined " + (colS === undefined));
  console.log("not " + !colS);
  console.log("void2 " + (colS == void 0));
  console.log("void3 " + (colS === void 0));
  console.log("== null ==");
  colS = null;
  console.log("null " + (colS === null));
  console.log("typeof " + ((typeof colS) === "undefined"));
  console.log("=undefined " + (colS === undefined));
  console.log("not " + !colS);
  console.log("void2 " + (colS == void 0));
  console.log("void3 " + (colS === void 0));
  console.log("== 0 ==");
  let colT = 0;
  console.log("null " + (colT === null));
  console.log("typeof " + ((typeof colT) === "undefined"));
  console.log("=undefined " + (colT === undefined));
  console.log("not " + !colT);
  console.log("void2 " + (colT == void 0));
  console.log("void3 " + (colT === void 0));
}

Output

if condition undefined null 0
var === null false true false
typeof(var) === 'undefined' true false false
var === undefined true false false
!var true true true
var == void 0 true true false
var === void 0 true false false

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I encountered a frustrating issue with saving user input data using localStorage

One of my goals is to store the current inputs even if the user refreshes or closes the browser. The issue I'm facing is that when I select Yes in the radio button, then refresh the page or close the browser and reopen it, the No button is checked wh ...

Adding style tags dynamically to a component and then encapsulating the styles again (using Angular)

Currently, I am in the process of upgrading from AngularJS to Angular. Our app is currently a hybrid one being bundled up with webpack instead of just angular cli. Due to this setup, we have encountered issues where our css or scss files are not correctly ...

Storing JSON data in a MongoDb database using the Sails.js framework

I'm looking to build my database using an external API. To begin, I've created a function called loadData(req, res){} in my DBController that retrieves data from the API in JSON format. Now, I want to save this imported JSON data into my mongoDB ...

Clickable Href in jquery autocomplete

These are the codes I am currently using: <link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"> <script src="//code.jquery.com/jquery-1.10.2.js"></script> <script src="//code.jquery.com/ui/1.1 ...

How can I reduce the number of pagination links in React js?

I need assistance in limiting the amount of pagination displayed on my website. Currently, I am fetching page numbers from the backend using Axios and useEffect, and then displaying them in JSX. However, I am struggling to limit the displayed numbers. Can ...

pull information from mongodb and connect it to google charts

I am looking to extract information from a MongoDB database to create a pie chart using Google Charts. In one scenario, I have a collection named "user" where each user has a boolean attribute called "paid." I want to calculate the number of paid and free ...

Is your $http request causing an XML parsing issue?

I'm attempting to utilize the $HTTP method from angularJS to access my restful web service. On entering my web service URL in the browser, I receive a result of APPLICATION/JSON type. {"id":20418,"content":"Hello, World!"} The URL for my web servic ...

Shut down the active tab

For some reason, using window.close(); in my JavaScript script is not closing the currently opened tab as expected. I'm looking for a way to automatically close a manually opened tab using a JavaScript function. Any ideas on what might be going wrong? ...

Most efficient method for comparing two JSON arrays and rearranging their positions

I am faced with a challenge involving two Javascript JSON arrays. The arrays in question are named this.BicyclePartsOLD and this.BicyclePartsNEW. Both arrays contain an attribute named "ListOrder". The OLD array is currently ordered from ListOrder 1 to n ...

connecting elements in an object's array to another array within a nested object

Is there a way to iterate through each string value in the imageKeys array and use it to create a URL for each object in the images array within the nested ImageList object, all without changing the original object? const myInitialStateFromParent = { ...

Troubleshooting auth error with Android and nativescript-plugin-firebase

I am currently utilizing this plugin in my application: https://github.com/EddyVerbruggen/nativescript-plugin-firebase Unfortunately, when using my real device on a 3G network, I encounter the following error: auth/network-request-failed Thrown if a netw ...

A guide to accessing the currently hovered element on a Line Chart with Recharts

Just diving into this community and also new to ReactJS :( https://i.stack.imgur.com/k682Z.png I'm looking to create a tooltip that displays data only when hovering over the value 1 line. Unfortunately, the current tooltip is not behaving as expecte ...

Eliminate a descendant of a juvenile by using the identification of that specific juvenile

Here is the current structure I'm working with: https://i.sstatic.net/TejbU.png I want to figure out how to eliminate any field that has the id 3Q41X2tKUMUmiDjXL1BJon70l8n2 from all subjects. Is there a way to achieve this efficiently? admin.databa ...

Arranging arrays of various types in typescript

I need help sorting parameters in my TypeScript model. Here is a snippet of my model: export class DataModel { ID: String point1: Point point2 : Point point3: Point AnotherPoint1: AnotherPoint[] AnotherPoint2: AnotherPoint[] AnotherPoi ...

Scan webpage for checkbox elements using JavaScript

When my page loads, dynamic checkboxes are generated using the following HTML: <input type='checkbox' name='quicklinkscb' id='quicklinkscb_XX'/> The XX in the ID represents the unique identifier of an item from the dat ...

What is the best way to refrain from utilizing the && logical operator within the mapStateToProps function in Redux?

When I'm trying to access a nested state in a selector, I often find myself having to use the && logical operators. const mapStateToProps = store => ({ image: store.auth.user && store.auth.user.photoURL; }); If I don't use ...

Trouble with basic JavaScript functionality in a React component

Here is a unique component code snippet: import React, {Component} from 'react'; import 'D:/School/Alta/interactiveweb/src/webapp/src/App.css' class Chat extends Component { test() { alert(); } render() { return <nav ...

Performing simultaneous document queries within a single API in MongoDB

I am currently working with an API written in typescript and attempting to execute parallel queries for the same document by using Promise.allSettled. However, I have noticed that it is performing poorly and seems to be running sequentially instead of in p ...

JavaScript (jQuery) module that fetches libraries

Many of you may be familiar with Google's API, which allows you to load specific modules and libraries by calling a function. The code snippet below demonstrates how this can be done: <script type="text/javascript" src="//www.google.com/jsapi"> ...

Eliminate viewed alerts by implementing a scrolling feature with the help of Jquery, Javascript, and PHP

My goal is to clear or remove notifications based on user scrolling. The idea is to clear the notification once the user has seen it, specifically in a pop-up window for notifications. I am relatively new to Javascript/jQuery and feeling a bit confused abo ...