The data type 'HTMLCollection | undefined' is required to have a method called '[Symbol.iterator]()' which will then return an iterator

I'm currently working on creating a custom date-picker using web components by following a tutorial. I've encountered an error while translating the JavaScript logic to Typescript, specifically within the connectedCallback() {...} function. The error message states:

Type 'HTMLCollection | undefined' must have a '[Symbol.iterator]()' method that returns an iterator
on this line of code:
const [prevBtn, calendarDateElement, nextBtn] = this.calendarDropdown?.querySelector(".calendar-header")?.children;
. Although I've researched similar issues on Stackoverflow, none of the suggested solutions seem to work for me. Can someone please help me understand what adjustments I need to make in order to resolve this error?

class DatePicker extends HTMLElement {
  shadow: ShadowRoot;
  calendar: Calendar;
  mounted: boolean = false;

  /** Elements */
  calendarDropdown: Element | null = null;
  calendarDateElement: HTMLHeadingElement | null | undefined = null;

  constructor() {
    super();
    ...
}

  connectedCallback() {
    this.mounted = true;

    this.toggleButton = this.shadow.querySelector(".date-toggle");
    this.calendarDropdown = this.shadow.querySelector(".calendar-dropdown");
    const [prevBtn, calendarDateElement, nextBtn] = this.calendarDropdown?.querySelector(".calendar-header")?.children; // <--- This is the line complain 
    this.calendarDateElement = calendarDateElement;

    this.toggleButton?.addEventListener("click", () => this.toggleCalendar());
    prevBtn.addEventListener("click", () => this.prevMonth());
    nextBtn.addEventListener("click", () => this.nextMonth());
  }
}

Answer №1

I discovered a helpful resource at which provided a workaround for my current issue. However, I am still searching for an even more effective solution to this problem. Instead of utilizing destructuring methods on child nodes of the parent node like shown below:

 const [prevBtn, calendarDateElement, nextBtn] = this.calendarDropdown?.querySelector(".calendar-header")?.children;
, I opted to individually locate and assign each node to a separate variable in the following code:

connectedCallback() {
...
   this.calendarDropdown = this.shadow.querySelector(".calendar-dropdown");
   const prevBtn = this.shadow.querySelector(".previous-month");
   const calendarDateElement =
     this.shadow.querySelector(".previous-month")?.nextElementSibling;
   const nextBtn = this.shadow.querySelector(".next-month");
   this.calendarDateElement = calendarDateElement;

   ...
   prevBtn?.addEventListener("click", () => this.prevMonth());
   nextBtn?.addEventListener("click", () => this.nextMonth());
}

Below is the complete class structure:

import { Calendar, Day } from ".";

class DatePicker extends HTMLElement {
  date: any = null;
  format = "MMM DD, YYYY";
  position: string | null = "bottom";
  visible: boolean | undefined = false;
  shadow: ShadowRoot;
  calendar: Calendar;
  mounted: boolean = false;

  /** Elements */
  toggleButton: HTMLButtonElement | null = null;
  calendarDropdown: Element | null = null;
  calendarDateElement: ChildNode | null | undefined = null;

  constructor() {
    super();

    const lang = window.navigator.language;
    const date = new Date(
      this.date ?? (this.getAttribute("date") || Date.now())
    );

    this.shadow = this.attachShadow({ mode: "open" });
    this.date = new Day(date);
    this.calendar = new Calendar(this.date.year, this.date.monthNumber, lang);

    this.format = this.getAttribute("format") || this.format;
    this.position = DatePicker.position.includes(
      this.getAttribute("position") as string
    )
      ? this.getAttribute("position")
      : this.position;

    this.visible =
      this.getAttribute("visible") === "" ||
      this.getAttribute("visible") === "true" ||
      this.visible;

    this.render();
  }

  connectedCallback() {
    this.mounted = true;

    this.toggleButton = this.shadow.querySelector(".date-toggle");
    this.calendarDropdown = this.shadow.querySelector(".calendar-dropdown");
    const prevBtn = this.shadow.querySelector(".previous-month");
    const calendarDateElement =
      this.shadow.querySelector(".previous-month")?.nextElementSibling;
    const nextBtn = this.shadow.querySelector(".next-month");
    this.calendarDateElement = calendarDateElement;

    this.toggleButton?.addEventListener("click", () => this.toggleCalendar());
    prevBtn?.addEventListener("click", () => this.prevMonth());
    nextBtn?.addEventListener("click", () => this.nextMonth());
  }

  // = this.calendarDropdown.sec
  //this.calendarDropdown?.querySelector(".calendar-header")?.children;

  prevMonth() {
    console.log("Prev Clicked");
    this.calendar.goToPreviousMonth();
    this.updateCalendarHeaderText();
  }
  
  ...

export default DatePicker;

window.customElements.get("date-picker") ||
  window.customElements.define("date-picker", DatePicker);

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

Verifying that objects are eligible for garbage collection

My program in node.js receives a high volume of messages. Each time a message is received, I create a new object and pass the message content to it. Inside the constructor of the new object, various operations are performed, including some mongo tasks with ...

The provisional headers provided by the local passport authentication strategy offer an added layer

When I send a POST request from my frontend with a username and password object, here is the code: const login = data => ( axios.post('http://localhost:3000/v1/user/login', data) .then(response => response.data) .catch((err) => ...

Guide to arranging components in two columns using VueJS Vuetify Grid

My goal is to align two components in order to display data on two columns. I followed the official Vuetify Grid tutorial, but encountered some issues with fixed row components. Despite trying to change from row to column, it still doesn't work as exp ...

Using TypeScript to map over unboxed conditions: transforming OR operators into AND operators

I am working with an array that has multiple objects containing functions foo. My goal is to create a new object signature with a function foo that inherits all the signatures from the array item foo functions. let arr = [ { foo: (a: 'a') = ...

Having trouble properly displaying information from a JSON array with jQuery

Having a basic array of data in a JSON file is presenting a challenge for a beginner like me when it comes to extracting the data. Here is the array that I have access to: var clients = [ { "clientid": "456489", "client-name": "John Smith", "e ...

Issue with external variable not being updated properly in success callback

Working through an array of data, I make updates to a variable called commentBody during each iteration. However, even though the variable is modified within the loop itself, whenever I try to access it from inside a success callback, it consistently show ...

How much time can pass between two clicks in order to activate a double-click event?

How long is the maximum delay between two clicks that will still activate a double-click event? Does this delay vary between plain JavaScript, jQuery, and AngularJS? Additionally, in jQuery, what time intervals do the fast and slow keywords represent? For ...

How to send variables to a method in a JavaScript modular pattern

I am trying to achieve something similar to the code snippet below. However, it seems to be invalid as it does not allow passing variables, specifically 'min' and 'max' in this case. Is there a way to achieve this functionality? If so, ...

Is it necessary to release an NPM package when creating a custom Javascript library for local use?

I want to organize my javascript utility functions in a central folder and access them from multiple projects. It appears that I am unable to import functions from outside the src file of my project. Do I need to create an NPM package? Must I duplicate t ...

Error: The function .default.auth.signout is not recognized in the REACT and Firebase environment

I've come across several error questions on StackOverflow, but most remain unanswered. The ones that are answered don't seem to solve my issue. I need help debugging this particular error. In my REACT project using Firebase, I'm working on ...

What could be causing the data toggle feature in my navbar to not work on Bootstrap?

Here is a code snippet to create a simple collapsible navbar with Bootstrap 5 that includes a logout button. However, the data toggle feature for the logout button doesn't seem to work when clicked. Any suggestions on how to fix this? <!DOCTYPE ...

When executing a JavaScript program, an error with the message 'MODULE_NOT_FOUND' appeared, causing the internal module loader in Node to throw an error at line 1145

node:internal/modules/cjs/loader:1145 throw err; ^ Error: Module 'C:\Users\sande\3D Objects\JavaScript-Lesson\lesson08.js' not found at Module._resolveFilename (node:internal/modules/cjs/loader:1142:15) at Mo ...

Is there a way to initiate an animation by clicking on something?

Currently, I have implemented requestAnimationFrame(loop); and I'm aiming to have an onclick button that triggers the animation. The setup involves clicking a button to initiate the animation process. I have the button structure set up as follows: < ...

I have discovered some amazing jQuery image hover effects that are simply breathtaking –

I have been using the Adipoli jQuery Image Hover Effects plugin, but I am facing issues with changing certain properties. The image is set to change to grayscale initially and then switch to color on hover. However, when I click on the image, it should mai ...

Confirming the data entry format

I am currently utilizing the RobinHerbots/Inputmask plugin to mask telephone input. I am interested in finding out how I can implement input validation to ensure that the user has entered accurate information. Thank you! <form> <input ty ...

AlphaVantage Platform: Element not found

As someone new to API services, I'm currently working on constructing a dashboard that pulls data from the Alphavantage API. My goal is to retrieve data for 3 symbols simultaneously by creating a list and passing the index to my API call. Each symbol ...

Steps for loading a different local JavaScript file by clicking on a button

My goal is to reload the browser page and display a different ReactJS component/file when a button is pressed. Initially, I attempted using href="./code.js" or window.location="./code.js" within the button props, but unfortunately, it did not yield the des ...

The submission feature for the textarea in Javascript is not functioning properly

As someone who is new to frontend development, I am currently facing a challenge with debugging JavaScript code that involves making changes to the content of a textarea. Despite my efforts to debug using the browser console, I have yet to identify why it ...

The ng-app feature is causing the script to run endlessly

Currently, I am troubleshooting an issue within my angular application that is built on the asp.net web application empty template. The problem arises when I utilize ng-app; if I leave it blank, the $routeProvider fails to initialize. However, if I specify ...

A method for assigning a single event listener to multiple events in a React component

I find myself in a situation where I have two events, onClick and onSelect, both of which share the same event handler. I am wondering what the most efficient way to handle this scenario would be - should I create a common method and then call the event ...