简体   繁体   English

如何将一个 Observable 对象数组转换为该对象数组中数据的 Observable?

[英]How do you turn an Observable array of objects, into an Observable of the data inside that array of objects?

I'm getting this error:我收到此错误:

Type 'Observable<Country[]>' is not assignable to type 'Observable'.类型“Observable<Country[]>”不可分配给类型“Observable”。 Type 'Country[]' is missing the following properties from type 'Country': name, tld, alpha2Code, alpha3Code, and 20 more.ts(2322类型“Country[]”缺少类型“Country”中的以下属性:name、tld、alpha2Code、alpha3Code 和 20 more.ts(2322


I think it's because the endpoint im reaching serves back an array with an object inside of it.我认为这是因为我到达的端点返回一个数组,其中包含一个对象。 Here's an example.这是一个例子。

https://restcountries.com/v3.1/name/peru https://restcountries.com/v3.1/name/peru


This is the code I can't get to work.这是我无法开始工作的代码。 It refuses to compile and gives me the error I posted above.它拒绝编译并给我上面发布的错误。

export class DetailsComponent implements OnInit {
  country$!: Observable<Country>
  countryBorders$!: Observable<Country[]>

  constructor(private apiService: ApiService, private activatedRoute: ActivatedRoute){}

  ngOnInit(): void {
    this.activatedRoute.params.subscribe((params) => {
      let countryName = params['country'];
      this.country$ = this.apiService.getCountryByName(countryName)
    });
    };
  }

The getCountryByName() method looks like this: getCountryByName() 方法如下所示:

  getCountryByName(name: string) {
    return this.http
      .get<Country[]>(`${this.api}/name/${name}`)
  }

How do I get the "this.country$" variable/observable/subject (idk what it is technically), to hold the data thats inside the object thats inside of the array that's being returned by the HTTP request?我如何获取“this.country$”变量/可观察/主题(idk 技术上是什么),以保存 HTTP 请求返回的数组内的对象内的数据?

I thought I could map the values out of the array, but this doesn't work either:我以为我可以将值映射到数组之外,但这也不起作用:

  ngOnInit(): void {
    this.activatedRoute.params.subscribe((params) => {
      let countryName = params['country'];
      this.country$ = this.apiService.getCountryByName(countryName).pipe(map(([info])=>return info)
    });
    };
  }

When I do that, I don't get the error but this template:当我这样做时,我没有得到错误,但是这个模板:

<div *ngIf="country$ | async as country">
  <h1>{{country$}}</h1>
</div>

renders渲染

[object Object]

...like the h1 on the page literally just says "[object Object]" ...就像页面上的 h1 字面意思只是说“[object Object]”


What am I doing wrong?我究竟做错了什么? What combination of operators do I need to use to convert the 'Observable<Country[]>' into just 'Observable<Country' so I can render it inside an html template like this?我需要使用什么运算符组合来将 'Observable<Country[]>' 转换为 'Observable<Country' 以便我可以在这样的 html 模板中呈现它?

  <div>
    <p><strong>Native Name: </strong>{{ country$.name.nativeName }}</p> 
    <p><strong>Population: </strong>{{ country$.population | number : '0.0' }}</p> 
    <p><strong>Region: </strong>{{ country$.region }}</p> 
    <p><strong>Sub Region: </strong>{{ country$.subregion }}</p> 
    <p><strong>Capital: </strong>{{ country$.capital }}</p></div>
    <div> 
      <p><strong>Top Level Domain: </strong>{{ country$.tld }}</p> 
      <p><strong>Currencies: </strong>{{ country$.currencies }}</p> 
      <p><strong>Languages: </strong>{{ country$.languages }}</p>
   </div>
</div>

This is the interface in case it's relevant to the answer:这是与答案相关的界面:

export interface Country {
  name: Name; //---
  tld: string[]; //---
  cca2: string;
  ccn3: string;
  cca3: string;
  cioc: string;
  independant: Boolean
  status: string;
  unMember: Boolean;
  currencies: Currency[]; //---
  idd: Idd;
  capital: string[]; //---
  altSpellings: string[];
  region: string;
  subregion: string; //---
  languages: any; //---
  translations: any;
  latlng: number[];
  landlocked: Boolean;
  borders: string[]; //---
  area: number;
  demonyms: any;
  flag: string;
  maps: Maps;
  population: number; //---
  gini: any;
  fifa: string;
  car: any;
  timezones: string[];
  continents: string[];
  flags: Flags;
  coatOfArms: COA;
  startOfWeek: string;
  capitalInfo: Capital;
  postalCode: Postal;
  // nativeName: string;
  // numericCode: string;
  // regionalBlocs: RegionalBloc[];
}

Looks like you have a typing issue in your getCountryByName method.看起来您的getCountryByName方法中存在输入问题。 Instead of .get<Country[]> , it should be .get<Country> :而不是.get<Country[]> ,它应该是.get<Country>

getCountryByName(name: string) {
  return this.http
    .get<Country>(`${this.api}/name/${name}`)
}

The RestCountries API returns the response with an array type. RestCountries API 返回具有数组类型的响应。 You can achieve with extract the first element of the array via map rxjs.您可以通过map rxjs 提取数组的第一个元素来实现。

getCountryByName(name: string): Observable<Country> {
  return this.http
    .get<Country[]>(`${this.api}/name/${name}`)
    .pipe(map((x) => x[0]));
}

The way you extract the properties from the country$ Observable is incorrect.您从country$ Observable 中提取属性的方式不正确。 You should look for an async pipe as what you have achieved in the question.您应该寻找一个async管道作为您在问题中取得的成就。

<div *ngIf="country$ | async as country">
  <div>
    <p><strong>Native Name: </strong>{{ country.name.nativeName | json }}</p>
    <p>
      <strong>Population: </strong>{{ country.population | number: '0.0' }}
    </p>
    <p><strong>Region: </strong>{{ country.region }}</p>
    <p><strong>Sub Region: </strong>{{ country.subregion }}</p>
    <p><strong>Capital: </strong>{{ country.capital }}</p>
  </div>
  <div>
    <p><strong>Top Level Domain: </strong>{{ country.tld }}</p>
    <p><strong>Currencies: </strong>{{ country.currencies }}</p>
    <p><strong>Languages: </strong>{{ country.languages }}</p>
  </div>
</div>

Demo @ StackBlitz 演示 @ StackBlitz

This was the correct format:这是正确的格式:

export class DetailsComponent implements OnInit {
  country$!: Observable<Country>
  countryBorders$!: Observable<Country[]>

  constructor(private apiService: ApiService, private activatedRoute: ActivatedRoute){}

  ngOnInit(): void {
    this.activatedRoute.params.subscribe((params) => {
      let countryName = params['country'];
      this.country$ = this.apiService.getCountryByName(countryName).pipe(map(([info])=>{return info}))
    });
    };
  }

I was doing it right.我做对了。 But in the template use:但在模板中使用:

<div *ngIf="country$ | async as country">
  <h1>{{country.name.common}}</h1>
</div>

NOT不是

<div *ngIf="country$ | async as country">
  <h1>{{country$.name.common}}</h1>
</div>

dumb mistake愚蠢的错误

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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