typescript 如何根据在不同组件中的单击来更改一个组件中的API数据

kuarbcqp  于 2022-12-14  发布在  TypeScript
关注(0)|答案(1)|浏览(127)

你好,我正在尝试学习Angular ,现在碰到了一堵墙。所以基本上我正在尝试做的是改变城市的天气数据,这是在一个组件后,在主页组件有4个城市的网格,每当用户点击任何一个它重定向到组件的数据(温度、时间湿度等),数据根据他在登陆主页上点击的城市而变化。目前日期固定为特定日期和城市。我对如何使这个工作以及组件之间的数据绑定如何工作感到非常困惑。有人能帮忙吗?
这是我的天气数据组件

<div>
    <p-table
      #dt
      [value]="lazyWeatherData"
      dataKey="id"
      [columns]="cols"
      [scrollable]="true"
      [tableStyle]="{ 'min-width': '50rem' }"
      scrollHeight="flex"
      [globalFilterFields]="['time','temperature','humidity','wind', 'pressure', 'direction', 'precipitation', 'rain', 'cloudcover','soilTemperature']"
      [rows]="10"
      [paginator]="true"
      [lazy]="true"
      (onLazyLoad)="loadData($event)"
      [loading]="loading"
    >
    <ng-template pTemplate="caption">
      <div *ngIf="filterSwitch" class="flex">
          <button pButton label="Clear"
          class="p-button-outlined"
          icon="pi pi-filter-slash"
          (click)="clearFilters(dt)">
        </button>
          <span >
              <i class="pi pi-search"></i>
              <input
              class="filter-input"
              pInputText
              type="text"
              (input)="dt.filterGlobal($event.target.value, 'contains')" />
          </span>
      </div>
  </ng-template>
      <ng-template pTemplate="header" let-columns>
        <tr class="icons">
          <th
          style="min-width:250px"
          [pSortableColumn]="col.field"
          *ngFor="let col of columns">
            <fa-icon [icon]="col.icon"></fa-icon>
            {{col.header}}
            <p-sortIcon [field]="col.field"></p-sortIcon>
            <p-columnFilter
            *ngIf="filterSwitch"
            [type]="col.type"
            display="menu"
            [field]="col.field">
          </p-columnFilter>
          </th>
      </ng-template>
      <ng-template pTemplate="body" let-lazy let-columns="columns">
        <tr>
          <td *ngFor="let col of columns">{{ lazy[col.field] + col.value }}</td>
        </tr>
      </ng-template>
    </p-table>
  </div>

这是数据表TS

export class WeatherDataComponent implements OnInit, OnDestroy {
  @ViewChild('dt') table: Table;
  showError: string;
  weatherData: WeatherDataItem[] = [];
  private componentDestroyed$: Subject<boolean> = new Subject();
  weatherDataLoading: boolean;
  icons: IconDefinition[] = [
    faClock,
    faTemperatureHigh,
    faPercent,
    faWind,
    faGem,
    faDirections,
    faWater,
    faCloud,
  ];
  cols: WeatherDataCol[];
  loading = false;
  lazyWeatherData: any = [];

  constructor(
    private weatherService: WeatherService,
    public datePipe: DatePipe
  ) {
    this.cols = [
      new WeatherDataCol('time', 'Time', 'text', '', this.icons[0]),
      new WeatherDataCol(
        'temperature',
        'Temperature',
        'text',
        '°C',
        this.icons[1]
      ),
      new WeatherDataCol('humidity', 'Humidity', 'numeric', '%', this.icons[2]),
      new WeatherDataCol('wind', 'Wind Speed', 'text', ' km/h', this.icons[3]),
      new WeatherDataCol(
        'pressure',
        'Air Pressure',
        'text',
        ' hPa',
        this.icons[4]
      ),
      new WeatherDataCol(
        'direction',
        'Wind Direction',
        'numeric',
        '°',
        this.icons[5]
      ),
      new WeatherDataCol(
        'precipitation',
        'Precipitation',
        'numeric',
        'mm',
        this.icons[6]
      ),
      new WeatherDataCol('rain', 'Rain', 'numeric', 'mm', this.icons[6]),
      new WeatherDataCol(
        'cloudcover',
        'Cloudcover',
        'numeric',
        '%',
        this.icons[7]
      ),
      new WeatherDataCol(
        'soilTemperature',
        'Soil Temperature',
        'text',
        '°C',
        this.icons[1]
      ),
    ];
  }

  ngOnInit(): void {
    this.weatherDataLoading = true;
    this.weatherService
      .getWeatherData()
      .pipe(
        finalize(() => (this.weatherDataLoading = false)),
        takeUntil(this.componentDestroyed$)
      )
      .subscribe({
        next: (historicalWeatherData) => {
          const temperatures = historicalWeatherData.hourly.temperature_2m;
          const times = historicalWeatherData.hourly.time.map((time) =>
            this.datePipe.transform(time, 'shortTime')
          );
          const humidities = historicalWeatherData.hourly.relativehumidity_2m;
          const windSpeeds = historicalWeatherData.hourly.windspeed_10m;
          const airPressures = historicalWeatherData.hourly.surface_pressure;
          const windDirections = historicalWeatherData.hourly.winddirection_10m;
          const precipitations = historicalWeatherData.hourly.precipitation;
          const rain = historicalWeatherData.hourly.rain;
          const cloudcover = historicalWeatherData.hourly.cloudcover;
          const soilTemperatures =
            historicalWeatherData.hourly.soil_temperature_0_to_7cm;

          temperatures.forEach((value, i) => {
            this.weatherData.push(
              new WeatherDataItem(
                value,
                times[i],
                humidities[i],
                windSpeeds[i],
                airPressures[i],
                windDirections[i],
                precipitations[i],
                rain[i],
                cloudcover[i],
                soilTemperatures[i]
              )
            );
          });
        },
        error: () =>
          (this.showError =
            'Something went wrong. Please try refreshing the page'),
      });
    this.loading = true;
  }

  loadData(event: LazyLoadEvent) {
    this.loading = true;
    setTimeout(() => {
      if (this.weatherData) {
        this.lazyWeatherData = this.weatherData.slice(
          event.first,
          event.first + event.rows
        );
        this.loading = false;
        console.log(this.lazyWeatherData);
      }
    }, 1000);
  }

  clearFilters(table: Table) {
    table.clear();
  }

  ngOnDestroy(): void {
    this.componentDestroyed$.next(true);
    this.componentDestroyed$.complete();
  }
}

这是一个主页组件,网格中有4个城市,当用户单击其中任何一个城市时,它会将用户重定向到上面的数据表,并应更改所单击城市的数据

<div class="container">
  <div class="grid">
    <a routerLink="/weather-data"><h3>London</h3></a>
    <a routerLink="/weather-data"><h3>New York</h3></a>
    <a routerLink="/weather-data"><h3>Tokyo</h3></a>
    <a routerLink="/weather-data"><h3>Sydney</h3></a>  
</div>

这是为家准备的

export class HomeComponent implements OnInit {
  constructor() {}

  ngOnInit(): void {}

}

这是从API获取数据天气服务

@Injectable({
  providedIn: 'root',
})
export class WeatherService {
  constructor(private http: HttpClient) {}

  getWeatherData(
    lat: string = '51.51',
    lon: string = '-0.13'
  ): Observable<WeatherData> {
    return this.http.get<WeatherData>(
      `https://archive-api.open-meteo.com/v1/era5?latitude=${lat}&longitude=${lon}&start_date=2005-08-25&end_date=2005-08-25&hourly=temperature_2m,relativehumidity_2m,dewpoint_2m,apparent_temperature,surface_pressure,precipitation,rain,cloudcover,windspeed_10m,winddirection_10m,soil_temperature_0_to_7cm`
    );
  }
}

基本上,我需要根据用户在主页中点击的城市更改天气服务URL中的纬度和经度,然后将其重定向到包含该城市更新数据的天气数据组件。我如何实现这一点?目前,纬度和经度默认设置为伦敦

3ks5zfa0

3ks5zfa01#

这个问题与如何将参数传递给weather-data. component有关。
如果组件在home.component中(不在路由器插座中),则使用@Input

//if I imagine you pass the lat and long separated by an space
@Input() set latLong(value)
{   
    const [lat,long]=value.split(' ')
    this.getData(lat,long)
}
getData(lat:string,long:string)
{
    //the code you put in ngOnInit but using lat and long
    this.weatherDataLoading = true;
    this.weatherService
      .getWeatherData(lat,long)
      .pipe(...
}

你的应用程序可以像这样

<li><button (click)="latlong='51.507222222222 -0.1275'">London</button></li>
<li><button (click)="latlong='40.416666666667 -3.7025'">Madrid</button></li>
<li><button (click)="latlong='48.856944444444 2.3513888888889'">Paris</button></li>

    <app-weather-data [latLong]="latlog"></app-weather-data>

如果没有父子关系,则有两种选择
1.在路由器的参数中传递数据。

{path:weather/:lat/:long,',component:WeatherDataComponent}

在ngOnInit中,您订阅了show docs之类的参数。请注意,您订阅了activatedRoute.queryParams,并使用switchMap返回weatherService.getWeatherData(lat,long)

constructor(private activatedRoute: ActivatedRoute,...){},
ngOnInit(){
  this.activatedRoute.queryParams.pipe(
    switchMap(params => {
    const lat=params['lat'];
    const long=params['long']

    return this.weatherService.getWeatherData(lat,long)
  }).subscribe(
    ...your function..
  });
}
}

1.或者像这样使用状态传递数据所以你的链接应该像这样

<a [routerLink]="['/weather']" [state]="{lat:'51.507222222222',long:'-0.1275'}">London</a>
    <a [routerLink]="['/weather']" [state]="{lat:'40.416666666667',long:'-3.7025'}">Madrid</a>
    <a [routerLink]="['/weather']" [state]="{lat:'48.856944444444',long'2.3513888888889')">Paris</a>

并且你在你的组件中使用(如果不是main)

this.activatedRoute.paramMap.pipe(
        take(1), //take(1) is for unsubscribe
        map(() => window.history.state),
        switchMap(res=>{
           return this.weatherService.getWeatherData(res.data.lat,res.data.long)

        })
    ).subscribe(res => {
       ..your code...
    })

或者,如果是主组件

this.router.events.pipe(
        filter(e => e instanceof NavigationStart),
        map(() => this.router.getCurrentNavigation().extras.state)
        switchMap(res=>{
           return this.weatherService.getWeatherData(res.data.lat,res.data.long)

        })
    ).subscribe(res => {
       ..your code...
    })

).subscribe(res=>{
   console.log(res)
})

注意:我不检查完整的代码,这是可能有一些语法错误,但我希望给予一些线索,以获得数据
NOTE2:也许这是更好的,是谁转换从一个WeatherDataTime数组中的URL接收数据的服务(使用Map),而不是组件.
顺便说一句,你应该在你的代码中做一些“东西”。我在你的代码中没有看到你使用“temperatures”数组(它是时间变量),什么都没有

相关问题