Mike Glaz
Mike Glaz

Reputation: 5382

Angular 4/5 - how to return proper object type from HttpClient's 'get'

I have a CRUD service and I need the get to return an object of type Event (i.e. a concert event).

I have the following:

query(): Observable<Event>{
  return this.http.get(this.apiUrl);
}

But this returns just json.

On Codecraft they suggest doing the following:

query(): Observable<Event>{
  return this.http.get(this.apiUrl).map(res => {
    return res.json().results.map(item => {
      return new Event(
        item.id,
        item.user_id,
        item.venue_id,
        item.timestamp,
        item.title,
        item.description
      )
    })
  });
}

however, .json() is not available on res. And neither is results nor map. I did import 'rxjs/add/operator/map'.

UPDATE ok, I used @Eduardo Vargas suggestion.

event.service.ts

import { Injectable } from '@angular/core';
import { Event } from './event';
import { HttpClient } from '@angular/common/http';
import { Response } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

@Injectable()
export class EventService {

  private apiUrl = 'http://localhost:3000/events';

  constructor(private http: HttpClient) {}

  query(): Observable<Event>{
    return this.http.get(this.apiUrl).map(item => item as Event);
  }

  get(id: number): Observable<Event>{
    return null;
  }

  save(event: Event): Observable<Event>{
    return this.http.post<Event>(this.apiUrl, event);
  }

  delete(event: Event): Observable<Event>{
    return this.http.delete<Event>(this.apiUrl + '/' + event.id);
  }

  update(event: Event): Observable<Event>{
    return null;
  }
}

event-index.component.ts

import { Component, OnInit } from '@angular/core';
import { Event } from '../event';
import { EventService } from '../event.service';
import { Router } from '@angular/router';
import { DataService } from '../../data.service';
import { Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-event-index',
  templateUrl: './event-index.component.html',
  styleUrls: ['./event-index.component.scss']
})
export class EventIndexComponent implements OnInit {
  event: Event;

  private events: Event[];

  constructor(
    private router: Router,
    private eventService: EventService,
    private data: DataService
  ) { }

  ngOnInit() {
    this.getEvents();
  }

  getEvents(){
    this.eventService.query().subscribe(
      events => {
        this.events = events;
      },
      err => {
        console.log(err);
      }
    )
  }

Everything seems to work, however this line this.events = events throws the following error:

ERROR in src/app/event/event-index/event-index.component.ts(32,9): error TS2322: Type 'Event' is not assignable to type 'Event[]'.

Upvotes: 2

Views: 3142

Answers (2)

Mike Glaz
Mike Glaz

Reputation: 5382

This seems to have done the trick...

query(): Observable<Event[]>{
  return this.http.get(this.apiUrl).map(item => item as Event[]);
}

Upvotes: 0

Eduardo Vargas
Eduardo Vargas

Reputation: 9392

You can use the as keyword from typescript.

query(): Observable<Event> {
  return this.http
    .get(this.apiUrl)
    .map(res => res.json())
    .map(item => item as Event);
}

Or if you are in a newer version of angular you can use the httpClient and then you don't need to map to json.

queryHTTPClient(): Observable<Event> {
   return this.httpClient
     .get(this.apiUrl)      
     .map(item => item as Event);
}

Typescript use duck typing "If it looks like a duck and quacks like a duck it is a duck." So if the response json looks like the Event interface you declared the 'as' keyword should work for you.

Upvotes: 2

Related Questions