Creating dynamic keys to insert objects

In my coding project, I am dealing with an empty array, a value, and an object. Since there are multiple objects involved, I want to organize them into categories. Here is an example of what I envision:

ARRAY 
  KEY
    OBJECT
    OBJECT
  KEY
    OBJECT

Initially, the array is empty as shown below:

public serviceTable: Services[] = [];

This is the interface for the array objects:

export interface Services {
  details:
    {
      service: string,
      description: string
    }
}

The object I receive from result looks like this:

data: {
  details: [
    {
      service: this.formMain.get('service')?.value,
      description: this.formMain.get('description')?.value
    }
  ]
}

Lastly, here is how I try to define the dynamic key for the array and its objects:

dialogRef.afterClosed().subscribe(result => {
  if (result) {
   if (!Object.keys(this.serviceTable)[result.section]) {
     // No section found, lets create it ...
     this.serviceTable[this.randomNumber] = [result];
     console.log(this.serviceTable, 'ServiceTable')
   }
   else {
     this.serviceTable[this.randomNumber].push()
   }
}

While the if-statement works fine, I encounter an issue with the else-statement leading to the error:

TS2339: Property 'push' does not exist on type 'Services'.

The error possibly occurs because

this.serviceTable[this.randomNumber]
is not recognized as an array.

If the key (this.randomNumber) doesn't already exist in the array, it will be created. However, if it does exist, I intend to add the new object under the same key.

Hence, I aim to iterate through the array and access all objects associated with a specific key, like this:

for (let item of this.serviceTable[3]) { // The number can also be replaced by a string, e.g., this.serviceTable['myCategory']
  console.log(item.service); // This should display all services linked to the key '3'
}

How can I achieve this functionality?


Check out an example of my code on StackBlitz.

Answer №1

Your primary issue lies within your user interface. While keeping the current setup, consider incorporating the following additional line:

export interface Sections extends Array<Services> {}

Furthermore, it might be necessary to update

public serviceTable: Services[] = [];

to

public serviceTable: Sections[] = [];

By utilizing an array in this manner, you can confidently employ

this.serviceTable[this.randomNumber].push(result)
without encountering any issues.

In alignment with your objective, here is a suggested approach for iterating through the array to extract objects based on a specific key:

// Similar to your existing code, but remember to include 'details'
for (let item of this.serviceTable[3]) {
 console.log(item.details.service);
}

Answer №2

Your code on Stackblitz is different from the code you have shown here, particularly in the definition of the Services interface. This difference is causing the issues you are facing (which also explains why your code was not compiling as expected)

In your question, the Services interface is defined like this:

export interface Services {
  details:
    {
      service: string,
      description: string
    }
}

However, in Stackblitz, it looks like this:

export interface Services {
  [details:number]:
    {
      service: string,
      description: string
    }
}

This results in a completely different data type. An instance of the first interface would look like this:

{ 
  details: {
    service: "foo",
    description: "bar"
  }
}

While an instance of the second interface would look like this:

{ 
  1: {
    service: "foo",
    description: "bar"
  }
}

In the second interface, the keys are numbers, making it similar to an array. This is why you were able to perform the assignment:

this.serviceTable[this.randomNumber] = [result];

However, since it's not actually an array, it does not have a push function (even though it may work at runtime because you are assigning a real array). This discrepancy causes a compilation error.

You also have a third type related to this issue, regarding the type of your result object:

data: {
  details: [
    {
      service: this.formMain.get('service')?.value,
      description: this.formMain.get('description')?.value
    }
  ]
}

If you try to assign

this.serviceTable[this.randomNumber] = [result];
, you will be trying to assign an incompatible array structure, as result contains a data property which is not present in the other types mentioned. The easiest solution might be to define the serviceTable as an array of arrays and use the original definition of the Services interface from your question rather than Stackblitz.

When creating the result object, you may need to adjust it to correctly match the updated structure, such as:

let result = {
  details: {
    service: this.formMain.get('service')?.value,
    description: this.formMain.get('description')?.value
  }
}

Or

let result = {
  data: {
    details: {
      service: this.formMain.get('service')?.value,
      description: this.formMain.get('description')?.value
    }
  }
}

Finally, if you intend to use push() with a value, that should also work with the modified definitions of serviceTable and result.

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

When the page loads, should the information be transmitted in JSON format or should PHP be responsible for formatting it?

I'm considering whether it would be more server-efficient and effective to send data to the user in JSON format upon page load, with JavaScript handling the conversion into readable information. For instance, when a user visits my index page, instead ...

Compilation of Angular 6 project is failing due to error TS1005: Expected ',' instead of the symbol used

I keep encountering an error message whenever I try to compile my code. ERROR in src/app/form/form.component.ts(22,39): error TS1005: ',' expected. Below is the snippet of code where the error is pointing: import { Component, OnInit } from &ap ...

The scrollOverflow feature in fullPage.js is not properly detecting the height of dynamically generated content

I have successfully implemented fullpage.js on my website. Everything is working perfectly with fullpage.js, but I am facing an issue when trying to open a div on click of pagination. Specifically, the browser scroll gets disabled when the div containing a ...

Troubleshooting a jQuery Selector Issue with a Dynamic Form

I developed a jQuery function to search for all the necessary inputs in a specific section of a website. function check_property_vars() { jQuery(this).parents('.property_group').find('div[id^="property_group_"]:input[required]:visible&a ...

Using NPM imports within a Node-RED node: A step-by-step guide

Is there a way to utilize NPM for handling dependencies in a Node-RED node instead of embedding the files directly into the packaged node? How can I set up a node so that it can leverage NPM to fetch package dependencies? ...

Comment sections that refresh automatically after being posted

I am determined to provide a clear explanation. Despite having some code, I am uncertain about how to make it clone comments and add new ones with user inputted text. Below is the snippet of code I am struggling with: <!DOCTYPE html> <!-- this i ...

Identifying keystrokes and triggering audio in Vue.js

Utilizing vue.js, the code snippet provided enables sound playback upon each button click. I am curious about how one can detect a keyboard press event to play a sound when the DOM is ready rather than waiting for button clicks. For instance, triggering ...

Using 'require' within a nested directive that relies on the parent directive in AngularJS

Implementing a sub directive to be utilized in multiple directives is my current challenge. These parent directives share a common controller that has useful methods for updating scope variables within these directives: (potentially changing controllers ...

What is the best way to safely store a logged-in user on the client-side?

As I delve into creating a login system for my simple social media website where users can make posts and view feeds from fellow followers, I've successfully implemented user login. Upon logging in, I'm able to retrieve the user's credential ...

Prevented: Techniques for providing extra cushioning for a button, but with the condition that it contains an external icon

How can I apply padding to a button only if it contains an external icon? If the button has an external icon, I want to give it padding-right: 30px (example). However, if there is no external icon present, then the button should not have the 30px padding. ...

Using AngularJS to Apply a Class with ng-repeat

Using ng-repeat in my markup, I am trying to add text to each li element and also include an additional class (besides the 'fa' class). This is what I have done so far: <ul class='social-icons' ng-repeat="social in myCtrl.socialArr" ...

Tips for resolving the 'JSX is not defined no-undef' error post TypeScript 4.4.2 update

Upon upgrading to TypeScript 4.4.2 from TypeScript 3.8.2, I have encountered numerous errors such as error 'x' is not defined no-undef. For instance, one of the errors is error 'JSX' is not defined no-undef. Upon closer inspection, most ...

Missing "this" after initialization? (typescript/node/express)

I am currently working on creating a basic http application using node-express. One issue I encountered is that when setting up routes, the constructor of the MyRouter class has access to this, but it seems to be lost within the getRoutes() function. cla ...

What steps can I take to resolve this issue when encountering an error during npm install?

As a newcomer to programming, I am embarking on the creation of a Discord bot using node and discord.js. My current hurdle involves the installation of a library named canvas, which seems to be causing issues. After developing and testing my application o ...

Tips on navigating an array to conceal specific items

In my HTML form, there is a functionality where users can click on a plus sign to reveal a list of items, and clicking on a minus sign will hide those items. The code structure is as follows: <div repeat.for="categoryGrouping of categoryDepartm ...

What is the best way to show information entered into a textbox on a different webpage?

Looking for advice on how to collect data in a text box and display it on another page? I have included HTML code for both the announcement page (where the data is entered) and the archive page (where the data should be shown). Could someone guide me on ...

Choose each day's time slot on the jQuery FullCalendar version 2.x

The code snippet below is a segment of the code generated by the FullCalendar jQuery plugin version 2. It has undergone some changes from version 1.x in terms of the classes it utilizes. <div class="fc-slats"> <table> <tbody> ...

Modify the size of images retrieved from the Twitch API

I have a request to the Twitch API to retrieve a list of top games and show their box art, but I'm facing an issue where the image will only display if I adjust the width and height values in the provided link. Is there a way to modify these values wi ...

Angular.js: Ensure all services are loaded before initializing the application

I am currently developing an application using angular.js and I need to ensure that the result from a specific service is accessible throughout the entire application right from the beginning. How can this be accomplished? The service in question is as f ...

Tips for extracting a keyword or parameters from a URL

I'm in the process of creating my personal website and I am interested in extracting keywords or parameters from the URL. As an illustration, if I were to search for "Nike" on my website, the URL would transform into http://localhost:3000/searched/Nik ...