What is the reason for a class's attributes being considered undefined even after they have been previously set?

Within my code, there is a class called WorkspaceDatabase that stems from the Dynamic Tree Example. I have incorporated some debugging information to gain a clearer understanding of the issue at hand.

The Issue:

Upon entering the complete() function, an unexpected occurrence arises: this.wsnodes.push results in a

TypeError: Cannot read property 'push' of undefined
, despite my belief that it was properly initialized.

Subsequently, when executing the getChildren function, a perplexing situation emerges where console.log(this.workspaces); yields an empty array. However, preceding this, the initialData() method executes and assigns the value of ws to this.workspaces, leading to a correct console output of

(7) [{…}, {…}, {…}, {…}, {…}, {…}, {…}]
.

I would appreciate if someone could shed light on what I might be overlooking here.

export class WorkspaceDatabase {

  workspacesService: WorkspacesService;
  workspaces: RQMWorkspace[] = new Array();
  wsnodes: WorkspaceFlatNode[] = new Array();


  setWorkspaceService(workspaceService: WorkspacesService) {
    this.workspacesService = workspaceService;
  }

  constructor() {
    this.wsnodes.push(new WorkspaceFlatNode(123, "test", true, 0, true));
    console.log("WorkspaceDatabase constructed");
  }

  initialData() {
    this.workspacesService.getWorkspaces().subscribe(
      {
        next(ws) {
          this.workspaces = ws;
          console.log(this.workspaces);
        },
        complete() {
          this.workspaces.forEach((ws) => {
            if (ws.workspace_id == null) {
              console.log(this.wsnodes);
              this.wsnodes.push(new WorkspaceFlatNode(ws.id, ws.name, true, 0, true))
            }
          });
          console.log("completed");
          console.log(this.wsnodes);
        }
      }
    );
  }

  getChildren(id: number): WorkspaceFlatNode[] | undefined {
    let children: WorkspaceFlatNode[] = new Array();
    console.log(this.workspaces);
    this.workspaces.forEach((ws) => {
      if (ws.workspaceId == id) {
        ws.workspaces.forEach((innerWs) => {
          children.push(new WorkspaceFlatNode(innerWs.id, innerWs.name, true, 0, true))
        });
        ws.documents.forEach((doc) => {
          children.push(new WorkspaceFlatNode(doc.id, doc.name, false, 0, true))
        });
      }
    })
    return children;
  }


}

Answer №1

When you are inside the complete() method, keep in mind that this refers to the current object being used, specifically the object passed as an argument to the subscribe() function, not the component itself.

It's recommended to utilize arrow functions for better functionality.

To see a demo, check out this link on stackblitz:

// this code does not work as expected
of('hello 1').subscribe({
  next(prefix) {
    console.log(prefix + ' ' + this.name);
  }
});

// this code works correctly
of('hello 2').subscribe(prefix => console.log(prefix + ' ' + this.name)
);

// another example of working code
of('hello 3').subscribe({
  next: prefix => console.log(prefix + ' ' + this.name)
});

Answer №2

complete function utilizes a syntax that differs in its use of this. Rather than passing traditional functions, consider using arrow functions which maintain the original this context.

initialData() {
    this.workspacesService.getWorkspaces().subscribe(
      ws => { //<--- arrow function

          this.workspaces = ws;
          console.log(this.workspaces);
        },
     err => {
        },
     () => { //<--- arrow function
          this.workspaces.forEach((ws) => {
            if (ws.workspace_id == null) {
              console.log(this.wsnodes);
              this.wsnodes.push(new WorkspaceFlatNode(ws.id, ws.name, true, 0, true))
            }
          });
          console.log("completed");
          console.log(this.wsnodes);
        }
    );
  }

If you happen to call the getChildren method before

this.workspacesService.getWorkspaces()
has finished execution, the this.workspaces array will not contain any data. It's only after
this.workspacesService.getWorkspaces()
completes that the workspaces array will be populated.

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

Tips for troubleshooting an Angular app with just a single click using WebStorm!

After conducting some research, I have checked the following resources: How to debug an application in Angular2 using angular-cli? https://manuel-rauber.com/2016/09/30/how-to-debug-angular-2-with-webstorm/ The troubleshooting method mentioned on the Je ...

Trouble installing Angular: ENOENT Error causing issues

Currently in the process of setting up angular. I have been diligently following the provided installation instructions, but when executing npm install -g @angular/cli, I encounter the error shown in the screenshot below. Here are the versions of node and ...

proper method for adding line breaks in json

I am experiencing difficulty in creating a line break using \r\n with the given payload on this particular screen. I am on a quest to determine the correct json payload that needs to be dispatched to the frontend in order for it to register as a ...

Learn how to define an object with string keys and MUI SX prop types as values when typing in programming

I want to create a comprehensive collection of all MUI(v5) sx properties outside of the component. Here is an example: const styles = { // The way to declare this variable? sectionOne: { // What type should be assigned here for SXProps<Theme>? } ...

Having trouble with your React/TypeScript/Redux/Thunk action not dispatching and the state remaining unchanged?

Currently, I am facing an issue while attempting to send a GET request to an API using React-Redux & TypeScript. The goal is to dispatch an action upon clicking a button (onClick event), make the request, update the state via the reducer, and finally log t ...

Angular 4: Issue with sending POST data via HTTP requests

I am currently working on developing a Web Application and I am facing an issue with testing the HTTP functions. Here is an example of my code snippet: import { Injectable } from '@angular/core'; import { Headers, RequestOptions, Http } from & ...

What could be causing my data to undergo alterations when transitioning from a frontend form submission to a backend API?

In my experience with Next.js 13 and Prisma, I encountered a peculiar issue. I had set up a basic form to collect user information for an api request. Oddly enough, when I printed the data right before sending it, everything seemed fine. However, upon arri ...

Modify the database entry only if the user manually changes it, or temporarily pause specific subscriptions if the value is altered programmatically

After a change in the viewmodel, I want to immediately update the value on the server. class OrderLine { itemCode: KnockoutObservable<string>; itemName: KnockoutObservable<string>; constructor(code: string, name: string) { ...

Is it possible to utilize @ViewChild() or a similar method with a router-outlet? If yes, how can it be

There is a recurring situation I encounter where I find myself wanting to access a child component located on the opposite end of a router outlet instead of through a selector: For example: <router-outlet></router-outlet> NOT: <selector-na ...

Tips on converting a date string in the format 'dd/MM/yyyy' to a date type using TypeScript

I have attempted the following code in order to convert the date from 'yyyy-mm-dd' format to 'dd/MM/yyyy'. However, when I check the typeof() of the result, it shows that it is a string. Is there a method to convert it into only a date? ...

The "ngx-phone-select" directive is not defined with the "exportAs" attribute

Having an issue with ngx-phone-select in the phone number field, receiving the error message "There is no directive with "exportAs" set to "ngx-phone-select" http://prntscr.com/hzbhfo This problem occurs in Angular 4.3 using ngx-phone-select version 1.0. ...

Error: The Class 'Subject<T>' does not properly extend the base class 'Observable<T>'

I encountered an error that says: **Build:Class 'Subject<T>' incorrectly extends base class 'Observable<T>** . I have TypeScript 2.4.1 installed and obtained angular quick starter files from the GitHub repository angular quick ...

Utilize the expert capabilities within #dateHeaderTemplate in the Angular component schedule by Syncfusion

I am trying to access the template #dateHeaderTemplate in order to retrieve the ID of the professional who is scheduled to attend the appointment. This information is needed to display the start and end times of the day in the header. By visiting this lin ...

Create a typescript class object

My journey with Typescript is just beginning as I delve into using it alongside Ionic. Coming from a background in Java, I'm finding the syntax and approach quite different and challenging. One area that's giving me trouble is creating new object ...

"Setting Up a Service in Angular: A Step-by-Step Guide

I am facing an issue with a root service that contains composition within it, as shown below: import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class MapService { private rmap: RMap; ini ...

Server Components can only receive plain objects and select built-ins from Client Components. Any classes or null prototypes will not be compatible

I am encountering an error when wrapping the App.ts with queryclientprovider: "Only plain objects, and a few built-ins, can be passed to Client Components from Server Components. Classes or null prototypes are not supported." Below is the code snippet from ...

The ngx-datatable is designed to bind only to the final comparator

When utilizing templates with ngx-datatable-column and binding comparator functions, only the final bound comparator is applied to all sortable columns. For instance: <div class="m-333"> <button mat-raised-button color="primary" (click)="openP ...

What is the best way to send information using an array of objects?

In my Angular 5 project, I am using the ngx select dropdown package (https://www.npmjs.com/package/ngx-select-dropdown) and I'm wondering how to pass an array of objects instead of an array of strings. Currently, when I do so, it displays [Object Obje ...

Issue with Material Sort functionality when null objects are present

I've encountered an issue with my code. I created a feature that adds empty rows if there are less than 5 rows, but now the sort function is no longer functioning properly. Strangely, when I remove the for loop responsible for adding empty rows, the s ...

Navigating with header tags and using the navbar in react-router

Here is the code snippet I am working with App.tsx import React, { FC, Fragment } from "react"; import Nav from "./Components/Nav/Nav"; const App: FC = () => ( <Fragment> <Nav /> </Fragment> ); export default App; Nav.tsx ...