Home > Net >  Why In-memory-web-api does not generate an ID?
Why In-memory-web-api does not generate an ID?

Time:08-22

I'm trying to use InMemoryDbService to simulate an API and make http requests with it. My GET,PUT and DELETE methods work but my CREATE method does not. Looks like the ID is not generated in the route to display my add form. I get this error in console : "url: 'api/pokemons/NaN'" and body : {error: "pokemons" with id = 'NaN' not found"

I have a lot of files so I'm not showing you the mock-pokemon-list.ts which is just an array of data. :) I've also removed the methods in my files that work to make it clearer and less difficult to read. I already tried to use this subject why genID() method in In-memory-web-api does not generate an ID? ... I hope my question is clear and easy to read. Sorry for the length of the files. Thank you all!

pokemon.module.ts (routes)

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes } from '@angular/router';
import { PokemonService } from './pokemon.service';
import { FormsModule } from '@angular/forms';
import { PokemonFormComponent } from './pokemon-form/pokemon-form.component';
import { AddPokemonComponent } from './add-pokemon/add-pokemon.component';

const pokemonRoutes: Routes = [
  { path: 'pokemon/add', component:AddPokemonComponent},
  
]
    
@NgModule({
  declarations: [
    PokemonFormComponent,
    AddPokemonComponent
    
  ],
  imports: [
    CommonModule,
    FormsModule,
    RouterModule.forChild(pokemonRoutes)
  ],
  providers: [PokemonService],
})
export class PokemonModule { }


in-memory-data-service.ts (we import data from mock-pokemon-list.ts which uses pokemon.ts class just after)

import { Injectable } from '@angular/core';
import { InMemoryDbService } from 'angular-in-memory-web-api';
import { POKEMONS } from './pokemon/mock-pokemon-list';

@Injectable({
  providedIn: 'root'
})
export class InMemoryDataService implements InMemoryDbService {

  createDb() {
    const pokemons= POKEMONS;
    return { pokemons };
  }
}

pokemon.ts

export class Pokemon {
    id:number;
    name:string;
    hp:number;
    cp:number;
    picture:string;
    types:string[];
    created:Date;

  constructor(
    name:string = 'Entrez un nom...',
    hp: number = 100,
    cp: number = 10,
    picture: string = 'https://assets.pokemon.coom/assets/cms2/img/pokedex/detail/xxx.png',
    types:string[] = ['Normal'],
    created: Date = new Date()
  ) {
    this.name=name;
    this.hp=hp;
    this.cp =cp;
    this.picture = picture;
    this.types = types;
    this.created = created;
  }
     
  
}

imports and add method in pokemon.service.ts

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Pokemon } from './pokemon';
import { catchError, Observable,of, tap } from 'rxjs';


@Injectable()
export class PokemonService {

  constructor(private http: HttpClient){}

 addPokemon(pokemon:Pokemon):Observable<Pokemon>{
  const httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/json'})
  };
  return this.http.post<Pokemon>('api/pokemons', pokemon, httpOptions).pipe(
    tap((response)=> this.log(response)),
    catchError((error)=>this.handleError(error, null))
  )
 }
 
  private log(response: any) {
    console.table(response);
  }
  private handleError(error: Error, errorValue: any) {
    console.error(error);

    return of (errorValue);
  }
  
}

add-pokemon.component.ts (a component which uses pokemon-form just below)

import { Component, OnInit } from '@angular/core';
import { Pokemon } from '../pokemon';

@Component({
  selector: 'app-add-pokemon',
  template: `
    <app-pokemon-form [pokemon]="pokemon"></app-pokemon-form>
  `,
})
export class AddPokemonComponent implements OnInit {

  pokemon:Pokemon;

  ngOnInit(): void {
    this.pokemon = new Pokemon();
  }

}

pokemon-form.component.ts

import { Component, Input, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { Pokemon } from '../pokemon';
import { PokemonService } from '../pokemon.service';

@Component({
  selector: 'app-pokemon-form',
  templateUrl: './pokemon-form.component.html',
  styleUrls: ['./pokemon-form.component.css']
})
export class PokemonFormComponent implements OnInit {

  @Input() pokemon:Pokemon;
  types: string[];
  isAddForm:boolean;

  constructor(
    private router:Router,
    private pokemonService: PokemonService
  ) { }


  ngOnInit()  {

    this.isAddForm = this.router.url.includes('add');
  }
    

  onSubmit() {
    if(this.isAddForm) {
      this.pokemonService.addPokemon(this.pokemon)
      .subscribe((pokemon: Pokemon)=> this.router.navigate(['/pokemon', pokemon.id]));
    }else {
      this.pokemonService.updatePokemon(this.pokemon)
      .subscribe(() => this.router.navigate(['/pokemon', this.pokemon.id])); 
    }
    
  }
}

my button which initiates the action

<a 
  style="position: fixed; bottom: 25px; right: 25px;" routerLink="/pokemon/add">   </a>

CodePudding user response:

I checked your code and see that. when you at /pokemon/add. not use AddPokemonComponent instead DetailPokemonComponent

const pokemonRoutes: Routes = [
  { path: 'edit/pokemon/:id', component: EditPokemonComponent},
  { path: 'pokemons', component: ListPokemonComponent },
  { path: 'pokemon/:id', component: DetailPokemonComponent},
  { path: 'pokemon/add', component: AddPokemonComponent},
]
  • Related