0

I am a beginner in angular and start to build my first app.My goal is to build a generic service that will be inherited from others service. I am following the structure of this link to my approach Generic HTTP Service .In read method i`m using Serializer class to convert the response json object to my typescript an it work. I got a map error. How can I solve it?

Service code:

import { Injectable } from '@angular/core';
import { Http, Headers } from '@angular/http';
import 'rxjs/add/operator/map';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Resource } from '../models/resource.model';
import { Observable } from 'rxjs/Observable';
import { Serializer } from '../serializer/serializer';
import { AuthenticationService } from './authentication.service';

@Injectable()
export class SharedService<T extends Resource> {

  constructor(
    private httpClient: HttpClient,
    private url: string,
    private endpoint: string,
    private authentication: AuthenticationService,
    private serializer: Serializer
  ) { }


  create(resource: T) {
    let headers = new HttpHeaders();
    headers = headers.set('Content-Type', 'application/json; charset=utf-8');
    return this.httpClient.post(`${this.url}/${this.endpoint}`, JSON.stringify(resource), { headers: headers });
  }



  //PUT
  update(item: T): Observable<T> {
    return this.httpClient.put<T>(`${this.url}/${this.endpoint}`, JSON.stringify(item), { headers: this.addHeaders() })
      .map(data => this.serializer.fromJson(data) as T);
  }



  //GET
  read(id: number): Observable<T> {
    return this.httpClient.get(`${this.url}/${this.endpoint}/${id}`, { headers: this.addHeaders() })
      .map((data: any) => this.serializer.fromJson(data) as T);
  }

  //GET ALL
  list(): Observable<T[]> {
    return this.httpClient.get<T>(`${this.url}/${this.endpoint}` , {headers : this.addHeaders()})
      .map((data: any) =>
        this.convertData(data.items));
  }

  protected convertData(data: any): T[] {

    return data.map(item => {this.serializer.fromJson(item)});
  }

  protected addHeaders() {
    let token = ('Bearer ' + this.authentication.getToken()).valueOf();
    let headers = new HttpHeaders();
    headers = headers.set('Content-Type', 'application/json; charset=utf-8').set('Authorization', token);
    return headers;
  }

}

UserService:

import { Injectable } from '@angular/core';
import { SharedService } from './shared.service';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { User } from '../models/user/user.model';
import { AuthenticationService } from 'app/service/authentication.service';
import { UserSerializer } from '../serializer/user-serializer';
import { NgForm } from '@angular/forms';

@Injectable()
export class UserService extends SharedService<User>{

  constructor(httpClient: HttpClient, authenticate: AuthenticationService) {
    super(httpClient,
      'http://localhost:8084/SuperCloud/webresources',
      'user',
      authenticate,
      new UserSerializer()
    );
  }

UserSerializer:

import { User } from "../models/user/user.model";
import { Serializer } from "./serializer";
import { Resource } from "../models/resource.model";

export class UserSerializer extends Serializer {
    fromJson(json: any): Resource {
        const user = new User();
        user.id = json.id;
        user.name = json.name;
        user.surname = json.surname;
        user.email = json.email;
        user.phoneNumber = json.phoneNumber;
        user.password = json.password;
        user.username = json.username;
        user.active = json.active;
        console.log('serializer');
        console.log(user);
        return user;
    }
}

User model:

import { Resource } from "../resource.model";

export class User extends Resource{
    username: string;
    email: string;
    name: string;
    surname: string;
    phoneNumber: string;
    password?: string;
    active : boolean;
}

UserService inherited inherited:

 ngOnInit() {
        this.userService.list().subscribe(
            (data) => console.log(data)
       );
 
    }

Error:

core.es5.js:1020 ERROR TypeError: Cannot read property 'map' of undefined

at UserService.SharedService.convertData (shared.service.ts:53)
at MapSubscriber.eval [as project] (shared.service.ts:48)
at MapSubscriber._next (map.js:79)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at MapSubscriber._next (map.js:85)
at MapSubscriber.Subscriber.next (Subscriber.js:95)
at FilterSubscriber._next (filter.js:90)
at FilterSubscriber.Subscriber.next (Subscriber.js:95)
at MergeMapSubscriber.notifyNext (mergeMap.js:151)
at InnerSubscriber._next (InnerSubscriber.js:25)

2 Answers 2

1

First of all, I assume the data that you passed into convertData function is not an array. Only Array or Observable have map function in this case. Also, chained function has been changed into pipeable operators in RxJS 6 https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md

Secondly, looking at the error message - I don't think the data value returned from the endpoint has value.

Third, data.map(item => {this.serializer.fromJson(item)}); - if the arrow function inside the map function is wrapped in curly bracket, you need to have return keyword. in other word, data.map(item => {this.serializer.fromJson(item)}); should be data.map(item => this.serializer.fromJson(item)); or data.map(item => {return this.serializer.fromJson(item)});

Sign up to request clarification or add additional context in comments.

3 Comments

Only the second it wasn't a problem.i change my code after your suggestions. list() : Observable<T[]>{ return this.httpClient.get(${this.url}/${this.endpoint}, { headers: this.addHeaders() }).pipe( map((data : T[]) => (this.convertData(data))) ) } protected convertData(data: any): T[] { return data.map(item => { return this.serializer.fromJson(item) }); }
The function is working!!Can i have a link really for beginners with pipe and chain examples
RxJS recently moved their documentation website to rxjs-dev.firebaseapp.com it's a good place to begin.
0

Use subscribe instead of map to return the response.

 return this.httpClient
  .put<T>(`${this.url}/${this.endpoint}`, JSON.stringify(item), {
    headers: this.addHeaders()
  })
  .subscribe(data => this.serializer.fromJson(data) as T);

BTW RXJs6 has changed the implementation of using observable map function

2 Comments

I have subscribe in my componet my problem is in list() function.
You can still subscribe in service class. list(): Observable<T[]> { return this.httpClient .get<T>(${this.url}/${this.endpoint}, { headers: this.addHeaders() }).subscribe((data: any) => this.convertData(data.items)); }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.