0

I am building this app in angular 6 which uses Rest Country API to fetch all the countries and their details. The problem I am facing is that I am not able to understand how to set routerLink in the parent component in order to fetch the details of the countries. Any suggestions would be appriciated. Thanks.

UPDATE

I am not able to understand how to access the name of the country in order to pass it to the URL. I tried almost everything I can think of but nothing seems to work.

Here are my files:

shared.modules.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CountryViewComponent } from './country-view/country-view.component';

@NgModule({
  imports: [
    CommonModule
  ],
  declarations: [
    CountryViewComponent
  ],
  exports: [
    CountryViewComponent,
    CommonModule
  ]
})
export class SharedModule { }

Child Component

country-view.component.ts

import { Component, OnInit, Input, OnDestroy } from '@angular/core';

// importing route related code
import { ActivatedRoute, Router } from '@angular/router';

//importing Service related code
import { CountryViewService } from '../../country-view.service';
import { CountryViewHttpService } from '../../country-view-http.service';

@Component({
  selector: 'app-country-view',
  templateUrl: './country-view.component.html',
  styleUrls: ['./country-view.component.css']
})

export class CountryViewComponent implements OnInit, OnDestroy {

  @Input() currentCountryName: String;

  public currentCountry;

  constructor(private _route: ActivatedRoute, private countryViewHttpService: CountryViewHttpService) {
    console.log("Contry View Constructor  Called");
  }

  ngOnInit() {

    // getting the name of the country from the route
    let myCountryName = this._route.snapshot.paramMap.get('currentCountryName');
    console.log(myCountryName);


    this.countryViewHttpService.getSingleCountryInfo(myCountryName).subscribe(

      data => {
        console.log(data);
        this.currentCountry = data;
      },
      error => {
        console.log("some error occured");
        console.log(error.errorMessage);
      }
    )
  }

  ngOnDestroy() {
    console.log("Country View Component Destroyed");
  }
}

Parent Component HTML

africa.component.html:

<!--Home page Html-->
<div class="container-fluid mainContainer">
  <div class="row mainRow">
    <div class="col mainCol">

      <!--Content Section-->
      <div class="row africanCountryRowHeading">
        <div class="backArrow">
          <a [routerLink]="['/home']">
            <i class="material-icons">
              keyboard_backspace
            </i>
          </a>
        </div>
        <div class="col-md-12 upperCol">AFRICA</div>
      </div>

      <a [routerLink]="['/country']">
        <div class="row africanCountryRowContent" *ngIf="allAfricanCountries.length>0">
          <div *ngFor="let africanCountry of allAfricanCountries" class="col-xs-12 col-md-6 col-lg-6 col-xl-6 africanCountriesMainCol">

            <!--Country Iteration div starts here-->
            <div class="row africanCountriesRow">
              <div class="col-md-12 africanCountryCol">
                <div class="panel-flag africanCountriesFlag">
                  <img [src]="africanCountry.flag">
                </div>
                <div class="panel panel-default africanCountriesPanel">
                  <div class="panel-heading africanCountriesPanelHeading">Country: {{africanCountry.name}}</div>
                  <div class="panel-body africanCountriesPanelBody">
                    <p>
                      Capital: {{ africanCountry.capital }}
                    </p>
                  </div>
                </div>
              </div>
            </div>
            <!--Countries Iteration div ends here-->
          </div>
        </div>
      </a>
    </div>
  </div>
</div>

Parent Component Module file

africa.module.ts:

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SharedModule } from '../shared/shared.module';
import { CountryViewComponent } from '../shared/country-view/country-view.component';
import { RouterModule, Routes } from '@angular/router';


@NgModule({
  imports: [
    CommonModule,
    SharedModule,
    RouterModule.forChild([
      { path: 'country/:name', component: CountryViewComponent }
    ])
  ],
  declarations: [CountryViewComponent]
})
export class AfricaModule { }

Child Component Service file

country-view-http.service.ts:

import { Injectable } from '@angular/core';

//importing Http Client to make the request
import { HttpClient, HttpErrorResponse } from '@angular/common/http';


//importing observables related code
import { Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { tap } from 'rxjs/operators';
import { delay } from 'rxjs/operators'


@Injectable({
  providedIn: 'root'
})

export class CountryViewHttpService {

  public currentCountries;
  public baseUrl = 'https://restcountries.eu/rest/v2/name';

  constructor(private _http: HttpClient) { 
    console.log("Country View Service Called");

  }

  // Exception Handler
  private handleError(err: HttpErrorResponse) {
    console.log("Handle error Http calls")
    console.log(err.message);
    return Observable.throw(err.message);
  }


  // method to return single country Informations
  public getSingleCountryInfo(currentCountryName): any {

    let myResponse = this._http.get(this.baseUrl + '/' + currentCountryName + '?fullText=true');
    console.log(myResponse);
    return myResponse;
  } // end get country info function
}

app.component.html

<div class="container-fluid mainContainer">
  <!--Navigation Secion-->
  <div class="row navigationMainRow">
    <div class="col-12 navigationMainCol">
      <div class="row navigationLogoRow">
        <div class="col-8 navigationLogoCol">
          <a [routerLink]="['/home']">
            <img src="../assets/images/Terra.png" alt="Logo" id="logo">
          </a>
        </div>

        <div class="col-4 navigationMenuCol">
          <div class="row navigationMenuRow">
            <div class="col-6 navigationLanguageCol">
              <p>
                Language
              </p>
            </div>
            <div class="col-6 navigationCurrencyCol">
              <p>
                Currency
              </p>
            </div>
          </div>  
        </div>
      </div>
    </div>
  </div>
</div>  
<router-outlet></router-outlet>

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';


// Router Module for Application level Route
import { RouterModule, Routes } from '@angular/router';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { AfricaComponent } from './africa/africa.component';
import { AmericaComponent } from './america/america.component';
import { AsiaComponent } from './asia/asia.component';
import { EuropeComponent } from './europe/europe.component';
import { OceaniaComponent } from './oceania/oceania.component'
import { FilterComponent } from './filter/filter.component';


// import statement for services
import { AfricaService } from './africa.service';
import { AfricaHttpService } from './africa-http.service';

import { AmericaService } from './america.service';
import { AmericaHttpService } from './america-http.service';

import { AsiaService } from './asia.service';
import { AsiaHttpService } from './asia-http.service';

import { EuropeService } from './europe.service';
import { EuropeHttpService } from './europe-http.service';

import { OceaniaService } from './oceania.service';
import { OceaniaHttpService } from './oceania-http.service';


@NgModule({
  declarations: [
    AppComponent,
    HomeComponent,
    AfricaComponent,
    AmericaComponent,
    AsiaComponent,
    EuropeComponent,
    OceaniaComponent,
    FilterComponent,
  ],
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      { path: 'home', component: HomeComponent },
      { path: '', redirectTo: 'main', pathMatch: 'full' },
      { path: 'africa', component: AfricaComponent },
      { path: 'america', component: AmericaComponent },
      { path: 'asia', component: AsiaComponent },
      { path: 'europe', component: EuropeComponent },
      { path: 'oceania', component: OceaniaComponent }
    ]),
    HttpClientModule
  ],
  providers: [AfricaService, AfricaHttpService, AmericaService, AmericaHttpService,
    AsiaService, AsiaHttpService, EuropeService, EuropeHttpService,
    OceaniaService, OceaniaHttpService],
  bootstrap: [AppComponent]
})
export class AppModule { }
Abhinav Alok
  • 120
  • 1
  • 1
  • 16

1 Answers1

1

Assuming that AfricaComponent is what you're referring to as the parent component, use the router link like:

<a [routerLink]="['/country', africanCountry]">{{africanCountry}}</a>

inside the *ngFor syntax.

You've already implemented routing in AfricaModule. Now you should be able to get the name of the africanCountry from a router params like this inside your CountryViewComponent:

let selectedCountryName;
this._route.params.subscribe((params) => {
  selectedCountryName = params['name'];
});

BTW, are you implementing AfricaModule as a Lazy Loaded module? If no, then call the forRoot method instead of the forChild method on RouterModule.

EDIT: You're not able to access the country name because you're trying to access the wrong state param name. You've defined the country name as name in your routes config. But you're trying to access it as a snapshot value of currentCountryName key which would not exist. Also using the snapshot to get state or query params isn't really a good practice as these might change asynchronously.

Have a look at this StackBlitz Project

This should definitely help

SiddAjmera
  • 38,129
  • 5
  • 72
  • 110
  • Thanks for your help, but it's not working. I am getting the error `Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'country/Algeria'` when I click on Algeria. (A country in Africa view) – Abhinav Alok Aug 17 '18 at 21:13
  • Did you change your `RouterModule.forChild` to `RouterModule.forRoot`? – SiddAjmera Aug 17 '18 at 21:16
  • Yes, I made the changes. – Abhinav Alok Aug 17 '18 at 21:21
  • Can you share the code of the template where your `router-outlet` is? I think this is because the `:name` part should be defined as a child path in the children section of the `country` path. – SiddAjmera Aug 17 '18 at 21:24
  • I am not sure that if this is what you are looking for (since I am still in the learning phase) but I have updated my question. Please, have a look. – Abhinav Alok Aug 17 '18 at 21:30
  • Have a look at the Updated Answer. I've created a StackBlitz project to help you check where exactly the issue is with your code. – SiddAjmera Aug 17 '18 at 21:39
  • Thanks a lot. I have been trying this since afternoon. :) But one thing though, We do we need to include the route in app.module.ts? I know, it's late but since you have helped so much. :) – Abhinav Alok Aug 17 '18 at 21:54
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/178225/discussion-between-abhinav-alok-and-siddharth-ajmera). – Abhinav Alok Aug 17 '18 at 21:56