Home > Back-end >  How do I show API response data in one component by calling it from another component?
How do I show API response data in one component by calling it from another component?

Time:08-24

I have two angular components. One with a dropdown thats list all countries and another component that displays holidays in a table based on the selection. The data doesn't show up on the html when selecting the country but I can console log the data and it shows up on the html if called directly from the second (table) component. Below are my codes. Since I am a beginner I am not sure what to do next and how to do it. Any help is appreciated. Thanks in advance.

Component for Dropdown .ts

import { Component, OnInit } from '@angular/core';
import { SCountryListService } from 'src/app/services/s-country-list.service';
import { SGenerateHolidaysService } from 'src/app/services/s-generate-holidays.service';
import { ViewHolidaysComponent } from 'src/app/tables/view-holidays/view-holidays.component';

@Component({
  providers: [ViewHolidaysComponent],
  selector: 'app-search-holidays',
  templateUrl: './search-holidays.component.html',
  styleUrls: ['./search-holidays.component.scss']
})
export class SearchHolidaysComponent implements OnInit  {

  public allCountryNames: any = [];
  public selectedCountry: string = '';

  constructor(private _receiveCountryNamesfromService: SCountryListService, private _selectedCountry: SGenerateHolidaysService, private _componentDataTable: ViewHolidaysComponent) { }

  ngOnInit(): void {
    
  }

  receiveCountryNames() { 
    this.allCountryNames = this._receiveCountryNamesfromService.generateCountryList();
    console.log(this.allCountryNames);
  }

  onSelectCountry(dropdownValue: string) { 
    console.log('selected '   dropdownValue);
    dropdownValue = 'US'; //Hardcoded for testing
    this._componentDataTable.holidays(dropdownValue);
  }
}

dropdown html .html

<h2>Select Country - Comp 1</h2>
<select  aria-label="Select a country" (focus)="receiveCountryNames()" (click)="onSelectCountry(dropdownValue.value)" #dropdownValue>
    <option selected>Select a country</option>
    <option value="{{country.code}}" *ngFor="let country of allCountryNames">{{country.code}}</option>
</select>

Component for the table .ts

import { Component, OnInit } from '@angular/core';
import { SCountryHolidaysService } from 'src/app/services/s-country-holidays.service'; 

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

  public allHolidays: any = [];

  constructor(private _getHolidaysFromApi: SCountryHolidaysService) { }

  ngOnInit(): void {
    
  }

  holidays(withCountryID: string) {
    console.log('Holiday Function Param -- '   withCountryID);
    this.allHolidays =  (this._getHolidaysFromApi.getHolidays(withCountryID)).subscribe(
      (data) => {
        this.allHolidays  = data;
        console.log(this.allHolidays);
      }
    )
  }

}
</select>

table html .html

<h2 >Holidays - Comp 2</h2>
<div >
<!-- Hardcoded button to display result on the table -->
    <button (click)="holidays('CA')">Get Holidays</button> 
    <table >
        <thead>
            <tr>
                <th scope="col">Date</th>
                <th scope="col">Local Name</th>
                <th scope="col">Name</th>
            </tr>
        </thead>
        <tbody>
            <tr *ngFor="let item of allHolidays">
                <td>{{item.date}}</td>
                <td>{{item.localName}}</td>
                <td>{{item.name}}</td>
            </tr>
        </tbody>
    </table>
</div>

Service 1: generate dropdown list

import { Injectable } from '@angular/core';
import countries from '../../assets/json/countries.json';

@Injectable({
  providedIn: 'root'
})
export class SCountryListService {

  constructor() { }

  generateCountryList(){
    let _countryFullName: any = new Array;
    for (var i = 0; i < countries.length; i  ) { 
      _countryFullName[i] = countries[i];
    }
    return _countryFullName;
  }
}

Service 2: generate api response

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';
import { CountryHolidays } from '../interfaces/country-holidays';


@Injectable({
  providedIn: 'root'
})
export class SCountryHolidaysService {

  public _holidayAPI: string = 'https://date.nager.at/api/v3/publicholidays/2022';

  constructor(private _http: HttpClient) { }

  getHolidays(countryCode: string): Observable<CountryHolidays[]> {
    console.log('getHolidays param -- '   countryCode);
    return  this._http.get<CountryHolidays[]>(`${this._holidayAPI}/${countryCode}`);
  }
}

json file for the countries .json

[{
        "name": "Australia",
        "code": "AU"
    },
.
.
.
.
]

Interface 1

export interface CountryNameID {
    name: string;
    code: string;
}

Interface 2

export interface CountryHolidays {
    date: Date,
    localName: string,
    name: string
}

CodePudding user response:

  1. Remove ViewHolidaysComponent from providers. providers is used for services not for components.

  2. You should either pass data from one component two another using Parent Child communication or using common service

Below are few steps you can use (Communication using service)

  1. Create a BehaviourSubject in SCountryHolidaysService

    selectedCountry$ = new BehaviorSubject('');

  2. In SearchHolidaysComponent component set value in this subject

    onSelectCountry(dropdownValue: string) { console.log('selected ' dropdownValue); dropdownValue = 'US'; //Hardcoded for testing this.sCountryHolidaysService.selectedCountry$.next(dropdownValue); }

  3. In ViewHolidaysComponent call API on value change of this subject

     allHolidays$ = this.sCountryHolidaysService.selectedCountry$.switchMap(
     (countryID) =>  this._getHolidaysFromApi.getHolidays(countryID));
    

use allHolidays$ using async pipe in template

CodePudding user response:

The problem is that you are trying to instantiate a component inside another component (table component inside dropdown component). This is not the way to go. You should rather create a service that is common to both components and is used to share data between both.

  • Related