【问题标题】:How can I use API call in *ngFor如何在 *ngFor 中使用 API 调用
【发布时间】:2019-02-28 10:44:26
【问题描述】:

我想在我的表格中按城市使用温度,如下所示。我有其他硬编码的数据,但是,需要从 API 获取温度数据。我从给定城市名称的 API 成功获取数据,但试图弄清楚如何在表格中呈现它。

组件文件

export class HomeComponent implements OnInit {

  events: Event[];
  selectedEvent: any;
  temperature:any;

  constructor(private eventService: EventService,
              private weatherService: WeatherService) { }


  loadTemperature(city: string){
    this.weatherService.getWeather(city).subscribe(data =>{
      this.temperature = data.current.temp_c;
    })

模板文件

<table class="table table-hover">
    <thead>
    <tr>
      <td>Event Id</td>
      <td>Event Name</td>
      <td>Session Time</td>
      <td>City</td>
      <td>Temperature</td>
      </tr>
    </thead>
    <tbody *ngFor="let event of events">
    <tr (click)="onSelect(event)">
      <td>{{event.id}}</td>
      <td>{{event.name}}</td>
      <td>{{event.time}}</td>
      <td>{{event.city}}</td>
      <td>{{**HERE I NEED TEMP BY CITY**}}</td>
    </tr>
    </tbody>
  </table>

请建议我解决这个问题的方法。 我使用了以下技巧但没有成功

<td *ngIf = "loadTemperature(event.city)">{{temperature}}</td>
<td>{{loadTemperature(event.city)}}</td>

【问题讨论】:

    标签: angular api


    【解决方案1】:

    我猜你不想要多个tbody标签,所以你应该把*ngFor放在&lt;tr&gt;上,此外你可以使用async管道来得到你想要的:

    <tbody>
      <tr *ngFor="let event of events" (click)="onSelect(event)">
        <td>{{event.id}}</td>
        <td>{{event.name}}</td>
        <td>{{event.time}}</td>
        <td>{{event.city}}</td>
        <td>{{ loadTemperature(event.city) | async }}</td>
      </tr>
    </tbody>
    

    您必须更改 loadTemperature 函数以返回 Observable

    loadTemperature(city: string): Observable<number> {
      this.weatherService.getWeather(city).pipe(
        map((data) => data.current.temp_c),
        shareReplay(1)
      });
    }
    

    我不完全确定这会对您的性能产​​生什么影响,它甚至可能会一遍又一遍地调用相同的 api,因为 *ngFor。也许添加trackBy 可以解决这个问题。

    不过,更好的是在events 中添加温度。但是为了给你看,我需要知道你是如何获得这个events数组的。

    考虑到您在某处对其进行了硬编码,您可以执行以下操作:

    events: Event[] = this.eventService.events;
    events$ = of(this.events).pipe(
      concatMap((events) => forkJoin(
        ...events.map((event) => this.loadTemperature(event.city).pipe(
          tap((temp) => event.temp = temp)
        )
      )
    );
    

    你需要更新你的模板来使用新的 observable:

    <tbody>
      <tr *ngFor="let event of events$ | async" (click)="onSelect(event)">
        <td>{{event.id}}</td>
        <td>{{event.name}}</td>
        <td>{{event.time}}</td>
        <td>{{event.city}}</td>
        <td>{{event.temp}}</td>
      </tr>
    </tbody>
    

    【讨论】:

    • 分号位置有错别字
    • @YoukouleleY 没了! ;)
    【解决方案2】:

    一般来说,在 *ngFor 中调用函数是一个“坏主意”(Angular “重绘” *ngFor 几次)。您必须使用 forkJoin 一起进行所有调用并更改数组。它或多或少像波纹管(注:我不检查代码,把它作为一个想法)

    AddTemperatures(events:any[])
    {
        //create an array of "calls" -an array of Observables-
         conts obs:Observable[]=events.map(even=>{
             return this.weatherService.getWeather(even.city);
         })
         //forkJoin realize all the calls together and
         //put the result in an array, so 
         //result[0] becomes the temperature of events[0].city
         //result[1] becomes the temperature of events[1].city ...
         return forkJoin(obs).pipe(map(result=>{
            //with result, for each event add the property "temperature"
            events.ForEach((event:any,index)=>{
               event.temperature=result[index]
            })
            }))
    }
    

    【讨论】:

      【解决方案3】:

      这是我对这个问题的看法。 我在主组件中创建了两个单独的组件。这是结构。

      主页组件 -- 事件列表组件 -- 事件组件

      现在我在列表组件中迭代了 ngFor 循环,如下所示。 事件列表组件

      export class EventListComponent implements OnInit {
      
        events: Event[];
      
        constructor(private eventService: EventService,
                   ) { }
      
        ngOnInit() {
          this.eventService.eventsChanged.subscribe((events: Event[]) => {
            this.events = events;
          });
          this.events = this.eventService.getEvents();
        }
      

      事件列表组件模板

          <div class="container-fluid">
        <div class="row text-center">
          <div class="col-sm-2">
            <b>Event ID</b>
          </div>
          <div class="col-sm-2">
            <b>Event Name</b>
          </div>
          <div class="col-sm-3">
            <b>Session Time</b>
          </div>
          <div class="col-sm-3">
            <b>City</b>
          </div>
          <div class="col-sm-2">
            <b>Temperature</b>
          </div>
        </div>
        <div class="row">
          <div class="col-sm-12">
            <app-event
              *ngFor="let e of events; let i = index"
              [event]="e"
              [index]="i">
            </app-event>
          </div>
        </div>
      </div>
      

      我使用了数据绑定,并为事件组件提供了一个事件。 事件组件

      export class EventComponent implements OnInit {
      
        @Input() index: number;
        @Input() event: Event;
        temp: string;
        constructor(private weatherService: WeatherService) { }
      
        ngOnInit() {
          this.loadTemperature(this.event.city);
        }
      
        loadTemperature(city: string) {
          this.weatherService.getWeatherByCity(city).subscribe(data =>{
            this.temp = data.current.temp_c;
          })
        }
      }
      

      事件组件模板

      <div class="container-fluid">
        <div class="row text-center" style="cursor: pointer; margin: 15px 0;"
             [routerLink]="index"
             routerLinkActive="active">
          <div class="col-sm-2">
            {{index}}
          </div>
          <div class="col-sm-2">
            {{event.name}}
          </div>
          <div class="col-sm-3">
            {{event.time}}
          </div>
          <div class="col-sm-3">
            {{event.city}}
          </div>
          <div class="col-sm-2">
            {{temp}}C
          </div>
        </div>
      </div>
      

      在事件组件中,我有一个事件,我可以通过 API 调用轻松地将温度分配给城市。

      谢谢大家的回答。

      【讨论】:

        【解决方案4】:

        试试这个方法-

        loadTemperature(city: string){
            return this.weatherService.getWeather(city).pipe(map(x => x.current.temp_c));
        <td>{{loadTemperature(event.city) | async}}</td>
        

        【讨论】:

        • 投反对票的你能帮我发表评论作为你的观点,而不是仅仅投反对票吗?
        • 所以你应该发表评论而不是仅仅对答案投反对票,无论如何都要检查函数是否数据来自 API
        • @PardeepJain 并不认为他投了反对票,但您正在返回订阅,并在上面使用 async。异步仅适用于可观察对象
        • 啊,是的,这可能是我的回答错误,感谢@PierreDuc 指出。无论如何,您的答案似乎已经解决了。
        • 请将subscribe替换为pipemap
        猜你喜欢
        • 1970-01-01
        • 2018-05-11
        • 2019-08-28
        • 1970-01-01
        • 2022-10-15
        • 2020-11-12
        • 2020-09-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多