简体   繁体   中英

Angular Property does not exist on type 'Object'

I'm having a few problems with Angular.

I'm trying to iterate through a JSON Api but I'm receiving the message "Property does not exist on type 'Object'.

Not exactly that, the error is "Property 'sprints' does not exist on type 'Project'"

I have this HTML template :

<mat-toolbar>
    <span>{{ currentProject.title }}</span>
</mat-toolbar>
<div class="data-panel">
  <mat-card>
    <mat-toolbar style="border-radius: 4px 4px 0px 0px;">
              <span>Development</span>
          </mat-toolbar>
          <mat-card-content>
            <span>Access Code: {{ currentProject.accessCode }}</span>
            <div *ngFor="let sprint of currentProject.sprints">  <---- THIS IS WERE THE ERROR HAPPENS
              <span>{{ sprint }}</span>
            </div>
          </mat-card-content>
  </mat-card>
</div>

And my JSON :

{
    "id": 1,
    "title": "App Komputer",
    "description": "Website dedicated to computer related products",
    "accessCode": "5128",
    "createdAt": "2022-01-13T21:19:11.000Z",
    "updatedAt": "2022-01-13T21:19:16.000Z",
    "sprints": [{
        "id": 1,
        "title": "Sprint 1",
        "releaseDate": "2022-01-20T21:37:13.000Z",
        "description": "Specs up to 01/22/2022",
        "createdAt": "2022-01-13T21:37:58.000Z",
        "updatedAt": "2021-12-13T01:46:36.000Z",
        "projectId": 1,
        "specifications": [{
            "id": 1,
            "title": "Add product button",
            "description": "New product button HTML",
            "duration": 10,
            "status": 1,
            "createdAt": "2021-12-23T01:46:36.000Z",
            "updatedAt": "2021-12-23T01:46:36.000Z",
            "sprintId": 1
        }]
    }]
}

Also, this is my Component :

constructor(
    private projectService: ProjectService,
    private route: ActivatedRoute,
    private router: Router,
    private _titleService: Title
    ) { }

  ngOnInit(): void {
    if (!this.viewMode) {
      this.message = '';
      this.getProject(this.route.snapshot.params["id"]);
    }
  }

  getProject(id: string): void {
    this.projectService.get(id)
      .subscribe({
        next: (data) => {
          this.currentProject = data;
          console.log(data);
          this._titleService.setTitle(data.title+' · Scrumy');
        },
        error: (e) => console.error(e)
      });
  }

How can I fix this error? I've tried many things but none worked.

Thank you!


EDIT 01/22/2022

For those who asked, here's the complete scheme of project-details-component.ts , where I get the function from:

import { Component, Input, OnInit } from '@angular/core';
import { ProjectService } from 'src/app/services/project.service';
import { ActivatedRoute, Router } from '@angular/router';
import { Project } from 'src/app/models/project.model';
import { Title } from "@angular/platform-browser";
import { Moment } from 'moment';
import { EChartsOption } from 'echarts';

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

  @Input() viewMode = false;

  @Input() currentProject: Project = {
    title: '',
    description: '',
    accessCode: ''
  };
  
  message = '';

  constructor(
    private projectService: ProjectService,
    private route: ActivatedRoute,
    private router: Router,
    private _titleService: Title
    ) { }

  ngOnInit(): void {
    if (!this.viewMode) {
      this.message = '';
      this.getProject(this.route.snapshot.params["id"]);
    }
  }

  getProject(id: string): void {
    this.projectService.get(id)
      .subscribe({
        next: (data) => {
          this.currentProject = data;
          console.log(data);
          this._titleService.setTitle(data.title+' · Scrumy');
        },
        error: (e) => console.error(e)
      });
  }

}

This is the project.model.ts :

export class Project {
  id?: any;
  title?: string;
  description?: string;
  accessCode?: string;
  createdAt?: Date;
  updatedAt?: Date;
}

Don't you also get errors for title and accessCode properties? Because you are mixing synchronous code with asynchronous and that's usually causing the issue you are facing.

To explain, your template expects that the currentProject is immediately available, which is not true, because you load it from some service. And depending on how long will that take your template wants to draw data from currentProject but it was not yet initialized.

If you don't want to rewrite your code to use async pipe, either put the whole block to *ngIf=",!currentProject", or add question marks before currentProject` properties.

<span>Access Code: {{ currentProject?.accessCode }}</span>
<div *ngFor="let sprint of currentProject?.sprints">
  <span>{{ sprint }}</span>
</div>

Comparing your JSON data and Product interface, you have missed out sprints property in your model.

Via json2ts , your Product interface should be as below:

export interface RootObject {
    id: number;
    title: string;
    description: string;
    accessCode: string;
    createdAt: Date;
    updatedAt: Date;
    sprints: Sprint[];
}

export interface Sprint {
    id: number;
    title: string;
    releaseDate: Date;
    description: string;
    createdAt: Date;
    updatedAt: Date;
    projectId: number;
    specifications: Specification[];
}

export interface Specification {
    id: number;
    title: string;
    description: string;
    duration: number;
    status: number;
    createdAt: Date;
    updatedAt: Date;
    sprintId: number;
}

Another concern is the concern mentioned by @mat, as currentProject data is asynchronous. Either you have to initialize the value to currentProject :

@Input() currentProject: Project = {
  title: '',
  description: '',
  accessCode: '',
  sprints: []
};

Or using Typescript optional chaining ( ?. ) to escape error when currentProject was null or undefined .

@Input() currentProject: Project;
<mat-toolbar>
  <span>{{ currentProject?.title }}</span>
</mat-toolbar>
<div class="data-panel">
  <mat-card>
    <mat-toolbar style="border-radius: 4px 4px 0px 0px;">
      <span>Development</span>
    </mat-toolbar>
    <mat-card-content>
      <span>Access Code: {{ currentProject?.accessCode }}</span>
      <div *ngFor="let sprint of currentProject?.sprints">
        <span>{{ sprint | json }}</span>
      </div>
    </mat-card-content>
  </mat-card>
</div>

Sample Demo on StackBlitz

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM