TypeScript Error: Attempting to slice an undefined property - TypeError

In my Angular project, I have a csv file containing data that is imported along with the D3.js library:

group,Nitrogen,normal,stress
banana,12,1,13
poacee,6,6,33
sorgho,11,28,12
triticum,19,6,1

The TypeScript file includes code for displaying a stacked bar chart:

import { Component, OnInit } from '@angular/core';
import * as d3 from 'd3';

@Component({
  selector: 'app-stacked-bar',
  templateUrl: './stacked-bar.component.html',
  styleUrls: ['./stacked-bar.component.css']
})
export class StackedBarComponent implements OnInit {

  data = [
    {"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
    {"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
    {"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
    {"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
  ];

  svg: any;

  margin = 50;
  width = 750 - (this.margin * 2);
  height = 400 - (this.margin * 2);

  ngOnInit(): void {

    this.createSvg();
    this.drawBars(this.data);
  }

  createSvg(): void {

    this.svg = d3.select("figure#stacked-bar")
    .append("svg")
    .attr("width", this.width + (this.margin * 2))
    .attr("height", this.height + (this.margin * 2))
    .append("g")
    .attr("transform", "translate(" + this.margin + "," + this.margin + ")");
  }

  drawBars(data): void {
 
    // List of subgroups - Header of the csv file.
    // Replace line below with ['Nitrogen', 'normal', 'stress'] to resolve issue
    const subgroups = data.columns.slice(1);
            
    const groups = data.map(d => (d.group));

    const x = d3.scaleBand()
    .domain(groups)
    .range([0, this.width])
    .padding(0.2);

    this.svg.append("g")
    .attr("transform", "translate(0," + this.height + ")")
    .call(d3.axisBottom(x).tickSizeOuter(0));
    
    const y = d3.scaleLinear()
    .domain([0, 60])
    .range([this.height, 0]);

    this.svg.append("g")
    .call(d3.axisLeft(y));

    const color = d3.scaleOrdinal()
    .domain(subgroups)
    .range(['#e41a1c','#377eb8','#4daf4a']);

    const stackedData = d3.stack()
    .keys(subgroups)
    (data);

    this.svg.append("g")
    .selectAll("g")
    .data(stackedData)
    .join("g")
    .attr("fill", d => color(d.key))
    .selectAll("rect")    
    .data(d => d)
    .join("rect")
    .attr("x", d => x(d.data.group))
    .attr("y", d => y(d[1]))
    .attr("height", d => y(d[0]) - y(d[1]))
    .attr("width", x.bandwidth());
  }
}

However, the plot appears empty, and upon inspecting the page, a console error displays:

TypeError: Cannot read property 'slice' of undefined

This error arises due to ambiguity in data, preventing the use of the slice method. A quick fix involves replacing subgroups with ['Nitrogen', 'normal', 'stress']. After making this adjustment, the chart renders successfully!

If anyone can provide assistance on this matter, it would be greatly appreciated.

p.s. For reference, here is how the chart should look:

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

Answer №1

If you are following the guidelines provided in this particular example, it's important to understand that the approach involves utilizing d3.csv for converting CSV data into an array of objects. D3 not only creates this array but also includes a custom columns property which is utilized within the example.

const csv = `group,Nitrogen,normal,stress
banana,12,1,13
poacee,6,6,33
sorgho,11,28,12
triticum,19,6,1`;

const data = d3.csvParse(csv);
console.log(data.columns);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

In case you're working with a similar array of objects in your code but without explicitly using the d3.csv method for importing CSV data, it indicates an alternative approach could be used for fetching the data.

In such circumstances, the equivalent of data.columns would be Object.keys(data[0]). Following this, you can employ slice to extract specific columns based on your grouping criteria:

const data = [
  {"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
  {"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
  {"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
  {"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
];

const dataColumns = Object.keys(data[0]);
console.log(dataColumns);

const subgroups = dataColumns.slice(1)
console.log(subgroups);
    

Answer №2

Would you mind giving the code below a shot?

 let groups = information.fields?.slice(2) || [];

Answer №3

It appears that in your code, the data object does not contain a property called columns.

The data was initially defined like this in the file:

data = [
    {"group": "banana", "Nitrogen": "12", "normal": "1", "stress": "13"},
    {"group": "poacee", "Nitrogen": "6", "normal": "6", "stress": "33"},
    {"group": "sorgho", "Nitrogen": "11", "normal": "28", "stress": "12"},
    {"group": "triticum", "Nitrogen": "19", "normal": "6", "stress": "1"}
  ];

Thus, the columns property is not present in the data.

Since data is already an array, it would be appropriate to use the following code:

const subgroups = data.slice(1)

Additionally, you seem to have implemented the groups variable correctly.

Answer №4

Currently, I am unable to personally test this approach, but based on my experience with TypeScript coding, many similar issues were resolved by specifying the variable type as 'any' like so:

const subgroups = (data as any).columns.slice(1)

However, please consider that my venture into web development was brief, so I cannot guarantee that this method will not have any negative effects on the overall code. Any feedback on this matter would be appreciated.

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

What are some solutions for troubleshooting setInterval issues?

I have a h1 element with a v-for loop that displays items from my array in the following format: <h1 v-for="(record, index) of filteredRecords" :key="index" :record="record" :class="get ...

Exploring the indexOf method in Jade

Currently using Jade and Express. '#{value.users}' is an array data type. '#{user.username}' is a string data type. Attempting to utilize the if '#{value.users}'.includes('#{user.username}') method. When true, I ...

What is the best method for automatically closing the modal window?

I implemented a modal window on my website. Within the modal, there is a green button labeled "Visit" which triggers the "Bootstrap Tour". I aim for the modal to automatically close when the tour starts. To access this feature on my site, users need to ...

Having trouble importing Bootstrap into Next.js? It seems like the issue may be related to the

I am currently facing an issue with importing bootstrap 5.3.2 (not react-bootstrap) into my NextJS 14.1.0 project that utilizes the new App Router. My goal is to strategically utilize individual Bootstrap components (not through data-attrs). I managed to ...

What is the best way to configure eslint or implement tslint and prettier for typescript?

In my React/Redux project, I recently started integrating TypeScript into my workflow. The eslint configuration for the project is set up to extend the airbnb eslint configurations. Here's a snippet of my current eslint setup: module.exports = { // ...

Eliminating an element from an array based on a single criterion

Here's a question that might seem simple to some: Let's say I have an array like this... var array = [ {id: 1, item: "something", description: "something something"}, {id: 2, item: "something else", description: "something different" ...

Tips for accessing $parent of ng-repeat from ng-include

In my code, I have a nested ng-repeat structure with an ng-include inside the inner ng-repeat. I am trying to access the outer ng-repeat using $parent within the ng-include. Here is an example of what I am working on: index.html <div ng-repeat="popula ...

Guide on transforming 3D obj files into particles using three.js

I've been experimenting with particles in three.js, but I've encountered an issue when trying to convert an obj file (3D model) into particles. Here are the code snippets I've been working with, but so far all my attempts have failed. Does ...

Retrieve all entries and merge a field with aggregated information in Mongoose (MongoDB)

I am faced with the challenge of working with two Mongo collections, Users and Activities. The Activities collection consists of fields such as createdAt (type Date), hoursWorked (type Number), and a reference to the user through the user field. On the oth ...

Is there a point at which embedding external JavaScript scripts becomes excessive?

Our main layout page contains some external scripts that are loaded after the page has fully loaded via ajax. Unfortunately, some of these scripts are quite slow as they are opening a socket.io connection, resulting in a delay in the overall page load time ...

Ways to display a different div when clicking on a div?

Good afternoon, I've noticed that this question has been asked numerous times before, but none of the solutions provided seem to work for my specific issue. My problem involves a div with the class .title3. I want another div with the class .Content ...

In JavaScript, the condition can function properly even without the "&&" logical operator, but if the "&&" is included, the condition does not operate

I need the error message to be shown if the character length in the #nameT id is less than 3 or greater than 20. When I use the && logical operator, it does not function correctly, as when the && is not present, it works perfectly when ex ...

Troubleshooting: Problems with Angular 2's [hidden] and *NgIf functionalities

My table displays a green circle if data is available in the gegevensAanwezig variable, which contains a school name, school code, and various booleans (Entreetoets, Eindtoets, etc) to indicate data availability. <tr *ngFor="let g of gegegevens ...

When utilizing Angular CDK virtual scroller, an error occurs stating that @angular/core/core does not have an exported member 'ɵɵFactoryDeclaration'. Can anyone explain why this is happening

After adding CDK Virtual Scroller to my ionic 5.3.3 project using the command: npm add @angular/cdk The version installed is: "@angular/cdk": "^13.0.2" The scroller viewport contains an ion-item-group: <ng-template #showContentBlo ...

Modify the CSS for the selected values in an angular material multi-select component

I am looking to customize the CSS for selected values in a material multi select. <mat-form-field class="mat-form-field-fluid"> <mat-select placeholder="User Permissions" [(value)]="selectedPermissions" multipl ...

Press on a rectangle inside an HTML5 SVG program

I'm currently developing a web application that utilizes the svg and Raphael library: workflowEditor.show(); var myList = document.getElementsByTagName("rect"); for (var a = 0; a < myList.length; a++) { myList[a].addEventListener("OnClick", f ...

Leveraging the power of node pkg to generate standalone executables while configuring npm

I have successfully used pkg to create an executable file for my node js application. Everything is working fine in that aspect. However, I am also utilizing the config module to load yaml configuration files based on the environment. During the packaging ...

Troublesome bug in Angular 7: [ngModel] functionality fails to cooperate with mat-select

Having trouble implementing ngModel in the following scenario: Check out the template code below: <mat-select [ngModel]="data.dataObject[0].phase"> <mat-option *ngFor="let phase of possiblePhases" [value]=" ...

Struggling to grasp the process of incorporating OAuth into both a REST API and a Single Page Application

I am currently working on integrating my SPA, DjangoRestframework, and auth0. My understanding is that the user registration process, as well as logging in and out, are all handled by Angular. Here are some key questions I need assistance with: 1. Aft ...

Vue has limitations when it comes to applying Template Syntax to buttons

Trying to make sense of the code in my Vue Component. All elements display the template from {{ title }}, except for one lone button that stubbornly shows the template syntax as plain HTML. See Generated Page for reference Snippet of My Code: <templat ...