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

The "angular2-image-upload" npm package encountering a CORS issue

Using the angular2-image-upload library for uploading files has been a smooth process until recently. After upgrading from version 0.6.6 to 1.0.0-rc.1 to access new features in future, I encountered issues with image uploads. The errors I faced were: htt ...

Obtaining access to a FormGroup instance when connected to a <form> through a directive

Question about HTML Form Directive <form [formGroup]="form"> <input type="text" formControlName="name" class="form-control" /> <div *errorFeedback name="name" class="error-feedback"></div> </form> Exploring Form Directiv ...

Comparing Angular 2 with Angular.js, React.js, and Typescript

Hello there, I am a fresh-faced web developer looking to create a modest website for my personal use. However, my knowledge is limited when it comes to JavaScript and jQuery concepts. In order to expand my skills and build an enhanced website, I decided ...

A guide on integrating the URI.js library into an Angular2+ application

I'm currently exploring ways to integrate a third-party library called urijs into my Angular 2+ application. Below, you can see the relevant files involved in this process. // package.json { ... "dependencies": { ... "urijs": "^1.18.10", ...

How can I extract a value from an object that is readonly, using a formatted string as the key?

I encountered a situation where I have code resembling the following snippet. It involves an object called errorMessages and multiple fields. Each field corresponds to various error messages in the errorMessages object, but using a formatted string to retr ...

Filtering database results from an Angular component

I am currently working on an Angular component and I have a result variable in the .ts file that stores data retrieved from the database. My goal is to filter this result variable to display only 20 records and sort them by date either in ascending or de ...

Allow Nest.js server to receive binary files in the request body

Is there a way to retrieve the uploaded binary file data from the browser? While the Nest.js server application functions correctly with Postman, it throws a 400 error when the request is sent from the Google Chrome/Angular application. Any ideas on how ...

Customize button appearance within mat-menu in Angular versions 2 and above

Is there a way to style my mat-menu to function similar to a modal dialog? I am having difficulty with the styling aspect and need advice on how to move the save and reset buttons to the right while creating space between them. I have attempted to apply st ...

Troubleshooting Problem with Kendo UI Integration in Angular 2

Attempting to follow the steps outlined in http://www.telerik.com/kendo-angular-ui/getting-started/ Encountered this error message in the browser console. No errors found on the server side. <button kendoButton (click)="onButtonClick()" [ERROR ->][ ...

Setting a timer in NGRX to control the interval between two actions

I am currently working with Angular and NGRX, and I have a requirement to implement a timer between two actions. The timer should start when the first action is triggered and stop when the second action occurs. I need to be able to store this timer in a gl ...

Here is a way to retrieve the name of a ref object stored in an array using Vue.js 3 and Typescript

I have a Form, with various fields that I want to get the value of using v-model and assign them to ref objects. In order to populate my FormData object with this data, I require both the name and the value of the ref objects. Unfortunately, I am struggli ...

Guide on implementing a .catch method in Firebase's onSnapshot function

I have recently developed an Ionic Firebase chat application. I seem to be encountering an issue with setting up a query snapshot when initializing the message page. Here is the code snippet that I am using: ngOnInit() { this.messageService.getA ...

Adding Dependencies to a Static Factory in Typescript

I have developed a service in typescript as a Class. Within this class, I have defined a static Factory where dependencies are injected. However, when I compress my application, the dependencies get compressed too, leading to an undefined provider error. ...

What causes Gun.js to generate duplicate messages within a ReactJs environment?

I need assistance with my React application where gun.js is implemented. The issue I am facing is that messages are being duplicated on every render and update. Can someone please review my code and help me figure out what's wrong? Here is the code s ...

How to pass parameters between pages in Ionic 2 using navParams when the return nav button is clicked

Is there anyone familiar with how to return a simple value (or JSON) by clicking on the return button in Ionic 2's navigation bar? I understand that navParam can be used to send a value when pushing a page, but I am unsure how to implement the same fu ...

Ways to showcase corresponding information for an item contained within an array?

I'm working with a function that is designed to retrieve specific descriptions for objects nested within an array. The purpose of the function (findSettings()) is to take in an array (systemSettings) and a key (tab12) as arguments, then use a switch s ...

Unlocking the power of global JavaScript variables within an Angular 2 component

Below, you will find a global JavaScript variable that is defined. Note that @Url is an ASP.Net MVC html helper and it will be converted to a string value: <script> var rootVar = '@Url.Action("Index","Home",new { Area = ""}, null)'; Sy ...

The data from the Subscribe API call is gradually loading within the ngOnInit() function

When using Angular 8, I am experiencing slow data retrieval when making API calls in the ngOnInit() function. The issue arises when trying to pass this data as @Input from one component module to another - it initially comes through as undefined for a minu ...

Record the variable as star symbols in the VSTS Extension

I am working on a VSTS extension using Typescript and utilizing the vsts-task-lib Currently, I am encountering an issue with the execSync function, which displays the command being executed. However, I need to hide a token obtained from a service by displ ...

Retrieve the dimensions of an image once rendering is complete, using Angular

I'm currently working on obtaining the rendered size of an image within a component. By utilizing the (load) event, I can capture the size of the image as it appears at that particular moment (pic1), as well as its "final" size after the page has fini ...