简体   繁体   中英

angular not displaying object attributes

I am following the HeroTutorial but using a Django backend. I have an Hero object that I am getting from DRF endpoint (verified with Postman). In my hero-detail.html the hero.name and hero.id are not displaying anything.

I know the hero object is being passed to the hero-detail.html because the browser shows the "Details" and "id:" so the line <div *ngIf="hero"> is telling me that there is a hero ..

But if there is a hero why does hero.name not show anything?

There are no errors in the browser console. The link to get to the hero-detail.component is coming from a dashboard.component which uses the same method but for some reason hero.name and hero.number work fine. The dashboard.component.html displays correctly so I know my services are working fine.

My hero-detail.html

<div *ngIf="hero">

<h2>{{hero.name | uppercase}} Details</h2>
<div><span>id: </span>{{hero.number}}</div>
<div>
  <label>name:
    <input [(ngModel)]="hero.name" placeholder="name">
  </label>
</div>

</div>

<button (click)="goBack()">go back</button>

hero-detail.component

import { Component, OnInit, Input } from '@angular/core';
import { Hero } from '../hero'
import { ActivatedRoute } from '@angular/router';
import { Location } from '@angular/common';
import { HeroService }  from '../hero.service';

@Component({
  selector: 'app-hero-detail',
  templateUrl: './hero-detail.component.html',
  styleUrls: ['./hero-detail.component.scss']
})
export class HeroDetailComponent implements OnInit {


  constructor(
  private route: ActivatedRoute,
  private heroService: HeroService,
  private location: Location
) {}

  @Input() hero: Hero;

  ngOnInit(): void {
    this.getHero();
  }

  getHero(): void {
    const number = +this.route.snapshot.paramMap.get('number');
    this.heroService.getHero(number)
      .subscribe(hero => this.hero = hero);
  }

  goBack(): void {
  this.location.back();
}

  }

dashboard.component

import { Component, OnInit } from '@angular/core';
import { Hero } from '../hero';
import { HeroService } from '../hero.service';

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: [ './dashboard.component.scss' ]
})
export class DashboardComponent implements OnInit {

  heroes: Hero[] = [];

  constructor(private heroService: HeroService) { }

  ngOnInit() {
    this.getHeroes();
  }

  getHeroes(): void {
    this.heroService.getHeroes()
      .subscribe(heroes => this.heroes = heroes.slice(1, 5));
  }
}

dashboard.html

<h3>Top Heroes</h3>
<div class="grid grid-pad">
  <a *ngFor="let hero of heroes" class="col-1-4"
      routerLink="/detail/{{hero.number}}">
    <div class="module hero">
      <h1>{{hero.name}}</h1>
    </div>
  </a>
</div>

hero.service

import { Injectable } from '@angular/core';
import { Hero } from './hero';
import { HEROES } from './mock-heroes';
import { Observable, of } from 'rxjs'
import { HttpClient, HttpHeaders } from '@angular/common/http'
import { catchError, map, tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})


export class HeroService {

private heroesUrl = 'http://127.0.0.1:8000/heroes/';  // URL to web api

  constructor(
  private http : HttpClient
) { }

  /**
 * Handle Http operation that failed.
 * Let the app continue.
 * @param operation - name of the operation that failed
 * @param result - optional value to return as the observable result
 */

  getHeroes (): Observable<Hero[]> {
  return this.http.get<Hero[]>(this.heroesUrl)

}

  getHero(number:number): Observable<Hero>{
    return this.http.get<Hero>(`${this.heroesUrl}${number}`);
  }

//  getHero(number: number): Observable<Hero> {
//  return of(HEROES.find(hero => hero.number === number));
//}


}

hero.service endpoint response from localhost:8000/heroes/2 , taken from Postman:

[
    {
        "name": "better hero",
        "number": 2
    }
]

also hero.service endpoint response from localhost:8000/heroes , taken from Postman:

[
    {
        "name": "bad hero",
        "number": 7
    },
    {
        "name": "bad hero",
        "number": 7
    },
    {
        "name": "better hero",
        "number": 2
    }
]

views.py

class HeroList(generics.ListAPIView):
    queryset = Hero.objects.all()
    serializer_class = HeroSerializer

    class Meta:
        model = Hero
        fields = ('number', 'name')


class HeroDetail(generics.GenericAPIView):
    serializer_class = HeroSerializer

 #TODO why do i need many=True here, this should returning one instance
    def get(self, request, number):
        # number = self.request.query_params.get('number')
        hero_detail = Hero.objects.filter(number=number)
        serializer = HeroSerializer(hero_detail, many=True)
        return Response(serializer.data)

    class Meta:
        model = Hero
        fields = ('number', 'name')

Looking at the sample API responses you've posted, it looks like retrieve method for a hero (/heroes/2 for instance) returns a list with only one item, instead of returning the item itself. In your client code though, you expect a hero object, not a hero list. Depending on your client code and for a rest api in general,

localhost:8000/heroes/2 should return

{
    "name": "better hero",
    "number": 2
}

not

[
    {
        "name": "better hero",
        "number": 2
    }
]

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