Implementing Dynamic Updates to a Google Sheets Custom Menu using Typescript

How to Automatically Update a Custom Menu in Google Sheets using Typescript

I have successfully set up the following: Dynamically Updating Custom Menu of Google Spreadsheet using Google Apps Script, a demonstration script for dynamically updating the custom menu of Google Spreadsheet using Google Apps Script.

In Typescript, I encountered an issue when clicking the menu item: Script function not found: Col1

Is there something missing while working with Typescript?

Main.ts

import { CustomMenu } from './ui/CustomMenu'

function onOpen() {
  CustomMenu.createMenu()
}

Main.gs

// Compiled using ts2gas 3.6.5 (TypeScript 4.3.2)
var exports = exports || {};
var module = module || { exports: exports };
//import { CustomMenu } from './ui/CustomMenu'
function onOpen() {
    //var menu = Menu.createMenu('Tracker')
    var menu = CustomMenu.createMenu();
}

CustomMenu.ts

export module CustomMenu {

  export function createMenu() {
    var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    var headers = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
    var ui = SpreadsheetApp.getUi();
    var menu = ui.createMenu('Custom Menu')
      .addItem('First item', 'menuItem1')
      .addSeparator();
    var subMenu = ui.createMenu('Sub-menu');
    for (var i = 0; i < headers.length; i++) {
      var dynamicMenu = headers[i];
      this[dynamicMenu] = dynamicItem(i);
      subMenu.addItem(dynamicMenu, dynamicMenu);
    }
    menu.addSubMenu(subMenu).addToUi();
  }
}

function dynamicItem(i) {
  return function() {
    var sheet = SpreadsheetApp.getActiveSheet();
    sheet.getRange(2, i + 1, sheet.getLastRow() - 1, 1).activate();
  }
}

CustomMenu.gs

// Compiled using ts2gas 3.6.5 (TypeScript 4.3.2)
var exports = exports || {};
var module = module || { exports: exports };
exports.CustomMenu = void 0;
var CustomMenu;
(function (CustomMenu) {
    function createMenu() {
        var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
        var headers = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
        var ui = SpreadsheetApp.getUi();
        var menu = ui.createMenu('Custom Menu')
            .addItem('First item', 'menuItem1')
            .addSeparator();
        var subMenu = ui.createMenu('Sub-menu');
        for (var i = 0; i < headers.length; i++) {
            var dynamicMenu = headers[i];
            this[dynamicMenu] = dynamicItem(i);
            subMenu.addItem(dynamicMenu, dynamicMenu);
        }
        menu.addSubMenu(subMenu).addToUi();
    }
    CustomMenu.createMenu = createMenu;
})(CustomMenu = CustomMenu || (CustomMenu = {}));
function dynamicItem(i) {
    return function () {
        var sheet = SpreadsheetApp.getActiveSheet();
        sheet.getRange(2, i + 1, sheet.getLastRow() - 1, 1).activate();
    };
}

Answer №1

Points of Revision:

  • Upon reviewing your script, it appears that the function is not being created when the menu for Col1 is executed.
  • It seems that the issue you are facing may be related to the line
    this[dynamicMenu] = dynamicItem(i);
    .
    • My observation suggests that the use of this within the function might not work as intended for installing the functions.

The error message Script function not found: Col1 is likely triggered by the aforementioned situation. To resolve this issue in your current script, I propose the following modification:

Revised Script:

In my response, I have adjusted your script as shown below.

Main.ts:

import { CustomMenu } from './ui/CustomMenu'

function onOpen() {
  CustomMenu.createMenu(this)
}

CustomMenu.createMenu(this)
  • Executing CustomMenu.createMenu(this) outside the onOpen function ensures that the function is dynamically created when invoked through the custom menu.

CustomMenu.ts:

export module CustomMenu {

  export function createMenu(obj) {
    var ss = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
    var headers = ss.getRange(1, 1, 1, ss.getLastColumn()).getValues()[0];
    var ui = SpreadsheetApp.getUi();
    var menu = ui.createMenu('Custom Menu')
      .addItem('First item', 'menuItem1')
      .addSeparator();
    var subMenu = ui.createMenu('Sub-menu');
    for (var i = 0; i < headers.length; i++) {
      var dynamicMenu = headers[i];
      obj[dynamicMenu] = dynamicItem(i);
      subMenu.addItem(dynamicMenu, dynamicMenu);
    }
    menu.addSubMenu(subMenu).addToUi();
  }
}

function dynamicItem(i) {
  return function() {
    var sheet = SpreadsheetApp.getActiveSheet();
    sheet.getRange(2, i + 1, sheet.getLastRow() - 1, 1).activate();
  }
}

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

Unable to find any routes that match child routes using the new Angular 2 RC1 router

ApplicationComponent import { Component } from '@angular/core'; import {Router, ROUTER_DIRECTIVES, Routes, ROUTER_PROVIDERS} from '@angular/router'; import {SchoolyearsComponent} from "./schoolyear/schoolyears.component"; @Component({ ...

Duplicate the ng-template using ng-content as the body (make a duplicate of ng-content)

I have been working on creating a feature that allows users to add custom columns to a PrimeNg table. The main reason for developing this feature is to provide users with a default table that already has numerous configuration options pre-set. However, I ...

Remix.js is unable to perform a redirect action when utilizing the Form component

I've been searching through the Remix documentation, but I can't seem to find a solution to my issue. It appears that you're unable to redirect from an action when using the Form component in Remix. You can check out this StackBlitz example ...

Creating TypeScript unit tests for nested functions: A step-by-step guide

I'm currently working with Angular 16 in combination with the ngRx framework. My development involves TypeScript coding and writing unit tests (.spec.ts) using Jasmine, especially for code similar to the example below. How do I invoke this method with ...

Challenges encountered when using promises for handling mysql query results

I've been working on creating a function that will return the value of a mysql query using promises. Here's what I have so far: query(query: string): string { var response = "No response..."; var sendRequest = (query:string): Prom ...

Step by step guide on transferring data from one Angular 7 component to another component following API response retrieval

I have been tackling an issue related to an API recently. Upon receiving a response from the API, my goal is to pass the value to a child component. In this component, I will run a method to obtain a response and display it on the screen. Example Code: ...

Angular 14 is throwing an error due to an indent issue - the expected indentation is 2 spaces but 4 spaces were found

Currently using "eslint": "^8.23.0" with angular 14. Everything was functioning properly with "eslint": "^8.22.0", but after updating to 8.23.0, I encountered the following error: https://i.sstatic.net/UALvS.png ...

Utilize cypress to analyze the loading time of a webpage

My current challenge involves using cypress to carry out website tests. I am looking for a reliable method to measure the duration it takes for certain cypress commands to load or execute. As an example: //var startTime = SomeStopwatchFunction(); cy.visit( ...

The ngAfterViewInit lifecycle hook does not get triggered when placed within ng-content

The ngAfterViewInit lifecycle hook isn't triggered for a Component that is transcluded into another component using <ng-content>, as shown below: <app-container [showContent]="showContentContainer"> <app-input></app-input> ...

Encountered Angular SSR Serve Error: NullInjectorError - StaticInjectorError in AppServerModule with the following reference:

While working on building an application with Angular's SSR and serving it, I encountered a specific error. All services and components have been properly injected. Error: ERROR Error [NullInjectorError]: StaticInjectorError(AppServerModule)[REQUEST] ...

Building an Angular 4 app featuring a customized default landing page and URL parameters functionality

I am in the process of developing a web portal that will be embedded within an iFrame. Below is the code snippet I am using to set up the portal: Routes Configuration const routes: Routes = [ { path: '', redirectTo: '/dash ...

Creating number inputs in Ionic 2/3 using alerts

I am currently working with Ionic 3.x on my macOS system. The issue I am facing is as follows: I have an array that contains a number and another array consisting of names. table: { number: number, names: string[] } = { number: 0, names: ['& ...

Only include unique objects in the array based on a common property

I am currently working with the following array: [ {name: "Mike", code: "ABC123"}, {name: "Sarah", code: "DEF456"}, {name: "John", code: "GHI789"}, {name: "Jane", code: "JKL01 ...

In Production mode, Angular automatically reloads the page every time my data request service is executed to fetch data from the API

The Issue at Hand I have developed an angular application that functions flawlessly on the development server. This application utilizes localStorage to store the user's JWT token, although I am aware that this may not be the most secure method. How ...

What is the best way to enhance the object type within a function parameter using TypeScript?

If I have a specified type like this: type Template = { a: string; b: string; c: string } I want to utilize it within a function, but with an additional parameter. How can I achieve this efficiently? When attempting to extend the type, TypeSc ...

Is there a way to import TypeScript modules from node_modules using browserify?

After successfully running tsc, I am facing difficulty understanding how to import TypeScript modules from node modules. The crucial section of my gulp file is as follows: gulp.task('compile-ts', ['clean'], function(){ var sourceTsF ...

Using Angular2 and Typescript to declare a variable of type "any" can result

Hello StackOverflow community, I am encountering an issue with my JavaScript code where a global variable is sometimes not defined. I have a configuration class in Angular2 that imports this global variable using 'declare var any'. Within the cl ...

Examining the array to ensure the object exists before making any updates in the redux

Is there a way to determine if an object exists in an array and update it accordingly? I attempted to use the find method, but it couldn't locate the specified object. I also tried includes, but it seems to be unable to recognize the item within the ...

Monitoring a Typescript Class's Get() or Set() function using Jasmine Spy

While working with Jasmine 2.9, I have encountered no issues spying on both public and private functions, except for when trying to spy on a get or set function at the class level. private class RandomService { public dogsHealth = 0; private get pers ...

Ensure your Vue components have type-checked props at compile time when using TypeScript

I have encountered an issue while using Vue.js with Typescript. The code I am working with is pretty straightforward, utilizing vue-class-component and vue-property-decorator. <script lang="ts"> import { Component, Prop, Vue } from 'vue-pro ...