【问题标题】:Angular Component renders before getting the data from backendAngular 组件在从后端获取数据之前渲染
【发布时间】:2021-06-22 03:58:08
【问题描述】:

我在一个页面上有两个组件:父级和子级。 父组件发出get请求getCityForecast(cityCode)并将数据绑定到子组件。

问题是子组件在父组件之前重新加载。并且没有填充数据。我该如何解决?

父组件

HTML

<div class="search-field">
  <input type="search" placeholder="Search..." [(ngModel)]="cityInput" (ngModelChange)="getAutoCompleteResults()">
  <button class="search-button">
    <svg id="search-icon" class="search-icon" viewBox="0 0 24 24">
      <path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"/>
      <path d="M0 0h24v24H0z" fill="none"/>
    </svg>
  </button>
  <div *ngIf="hasSearchResults()">
    <p *ngFor="let city of autoCompleteSearchResults" (click)="cityChoice(city.LocalizedName, city.Key); getCityForecast(city.Key)">{{city.LocalizedName}}</p>
  </div>
</div>

<app-todays-forecast
  [city]="cityDetails"
  [todaysForecast]="todaysForecast">
</app-todays-forecast>

TS

import { Component, OnInit } from '@angular/core';
import { DataFetchService } from '../services/data-fetch.service';
import { HttpClient } from '@angular/common/http';

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

  autoCompleteSearchResults: any;
  cityInput: string = '';
  cityDetails: any = {};
  defaultCityCode = 210841;
  defaultCityName: string = 'Tel-Aviv';
  todaysForecast: any;

  constructor(private fetchData: DataFetchService,
    private http: HttpClient) { }

  ngOnInit(): void {
    this.cityDetails.name = this.defaultCityName;
    this.getCityForecast(this.defaultCityCode);
    console.log(this.todaysForecast);
  }

  hasSearchResults() {
    return this.autoCompleteSearchResults?.length > 0;
  }

  cityChoice(name, key) {
    this.cityDetails.name = name;
    this.cityDetails.key = key;
  }

  getAutoCompleteResults() {
    this.fetchData.fetchAutoCompleteResults(this.cityInput)
      .subscribe(
        result => { this.autoCompleteSearchResults = result },
        err => console.log(`we have an error: ${err}`)
      )
  }

  getCityForecast(cityCode) {
    this.fetchData.getCityForecast(cityCode)
    .subscribe(
      result => this.todaysForecast = result[0],
      err => console.log(`we have an error: ${err}`)
    );
  }

子组件

HTML

<h1>Today's Weather in {{city.name}}</h1>
<p>Temperature: {{temperature}}°С</p>
<p>Weather: {{conditions}}</p>

TS

import { Component, OnInit, Input } from '@angular/core';
import { DataFetchService } from 'src/app/services/data-fetch.service';
import { HttpClient } from '@angular/common/http';

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

  @Input() city: any;
  @Input() todaysForecast: any;

  temperature: any;
  conditions: any;

  constructor( public fetchData: DataFetchService) { }

  ngOnInit(): void {
    console.log('this.todaysForecast >>>', this.todaysForecast);
    this.temperature = this.todaysForecast?.Temperature.Metric.Value;
    this.conditions = this.todaysForecast?.WeatherText;
  }

}

【问题讨论】:

    标签: angular typescript


    【解决方案1】:

    不要使用 ngOnInit,而是在 @Input 中使用“setter”

    @Input() todaysForecast(value){
        this.temperature = value.Temperature.Metric.Value;
        this.conditions = value.WeatherText;
        //is you need it you can also use another variable "_todayForecast
        //this._todayForecast=value
    }
    //and a getter
    get todayForecast(){
       return this._todayForecast
    }
    

    实现 OnChanges

    export class TodaysForecastComponent implements OnChanges {
      @Input() todaysForecast;
    
      ngOnChanges(changes: SimpleChanges) {
        // changes.prop contains the old and the new value...
      }
    }
    

    【讨论】:

    • 我使用了getter 并将*ngIf 添加到我的子组件中。谢谢!
    【解决方案2】:

    有几种方法可以做到:

    • 有条件地在父模板*ngIf="data"中显示子组件,其中data是从后端检索到的数据
    • 使子组件以特定方式处理nullundefined
    • 在子组件中传播Observable(通常更复杂,不符合智能/哑组件原则)

    【讨论】:

      【解决方案3】:

      如果您想在渲染组件之前获取数据,您可以使用解析器。

      https://angular.io/api/router/Resolve

      【讨论】:

      • 真的我觉得用Revolve更适合其他情况(解决这个问题可以用更简单的方式解决)
      • 你说得对@Eliseo。解析器只是在您需要在加载路线之前使用的时候,但事实并非如此。您的方法更简单,更准确。谢谢!
      猜你喜欢
      • 2018-02-19
      • 2020-03-17
      • 2019-08-01
      • 2019-02-08
      • 2022-01-24
      • 2021-07-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多