1

I am trying to map a http response to a JSON and then map part of that JSON to a Ticket interface as it has many values I don't need in my ticket interface. My app compiles without any issues but when I test the REST function I get the below runtime error, I know the issue isn't with the backend as I'm able to successfully console log the response. Any idea what I'm doing wrong here?

My error:

    vendor.bundle.js:8137 Angular is running in the development mode. Call enableProdMode() to enable the production mode.
    main.bundle.js:553 TypeError: res.json(...).map is not a function
        at MapSubscriber.project (main.bundle.js:1330)
        at MapSubscriber._next (vendor.bundle.js:42853)
        at MapSubscriber.Subscriber.next (vendor.bundle.js:4709)
        at XMLHttpRequest.onLoad (vendor.bundle.js:47289)
        at ZoneDelegate.webpackJsonp.749.ZoneDelegate.invokeTask (polyfills.bundle.js:2478)
        at Object.onInvokeTask (vendor.bundle.js:9228)
        at ZoneDelegate.webpackJsonp.749.ZoneDelegate.invokeTask (polyfills.bundle.js:2477)
        at Zone.webpackJsonp.749.Zone.runTask (polyfills.bundle.js:2245)
        at XMLHttpRequest.ZoneTask.invoke (polyfills.bundle.js:2540)


My code:

    retrieveTicket(barcode: string) : Observable<any> {
          return this.http.get(`${this.API_URL}POS/RetrieveTicket/${barcode}`, this.options)
          .map((res: Response) => res.json().map(ticket => {          
                Object.assign({
                    ResponseCode: ticket.ResponseCode,
                    CustomError: ticket.CustomError,
                    ticketDate: ticket.POSTicket.Date,
                    ticketTime: ticket.POSTicket.EndTime,
                    cashierName: ticket.POSBarCode.POSCashier_Name,
                    tranNo: ticket.POSTicket.TranNo,
                    tranValue: ticket.POSTicket.ScanValue,
                    securityChecked: ticket.POSBarCode.SecurityChecked
                }) as ITicket})         
          )
          .catch((error: any) => Observable.throw(error || 'server error'));
      } 


 my interface:

        import { BaseRequestInterface } from './base-request.interface';

        export interface ITicket extends IBaseRequest {
            ticketDate: string;
            ticketTime: string;
            cashierName: string;
            tranNo: string;
            tranValue: string;
            timeSincePurchase: string;
            securityChecked: boolean;

            export function setTicket(obj?: any) {
                super();
                this.ResponseCode = obj && obj.ResponseCode || null;
                this.CustomError = obj && obj.CustomError || null;
                this.ticketDate = obj && obj.ticketDate || null;
                this.ticketTime = obj && obj.ticketTime || null;
                this.cashierName = obj && obj.cashierName || null;          
                this.tranNo = obj && obj.tranNo || null;
                this.tranValue = obj && obj.tranValue || null;
                this.timeSincePurchase = obj && obj.timeSincePurchase || null;
                this.securityChecked = obj && obj.securityChecked || null;
            }


        }

my BaseRequest Interface:

//  Base request class that returns from BRMService API
export interface IBaseRequest {
    //  Public properties available
     BaseURI?: string;
     CustomError?: string;
     ProviderName?: string;
     RequestFormData?: string;
     RequestURI?: string;
     ResponseCode?: number;    
}
0

1 Answer 1

1

EDIT:

We learned that we are dealing with just one Object, rather than an array of object, so mapping the object to type TicketModel would be done like the following (shortened):

retrieveTicket(barcode: string) {
   return this.http.get(...)
     .map(res => res.json())
     .map(res => ({ResponseCode:res.ResponseCode, CustomError:res.CustomError}) as TicketModel)
}

The interface:

export interface TicketModel {
  ResponseCode: number; 
  CustomError:string 
}

DEMO


ORIGINAL POST:

Unclear if you are using a class or interface for your TicketModel, anyway I suggest you use an interface ;) Then you can simply map your incoming data like (shortened version):

.map((res:Response) => res.json().map(x => 
   Object.assign({ResponseCode: x.ResponseCode, 
                  CustomError:x.CustomError}) as TicketModel)))

If your response is an object with an array containing inside items, just add the items in:

.... res.json().items.map( ...
Sign up to request clarification or add additional context in comments.

12 Comments

I added my ticketModel to the bottom of my question. Any idea why it's not working with this model/giving me the undefined error? Thanks for your effort...
You don't really need to use a class here, since you have class dependent functions. Just use an interface, that's my advice :) Also you are not exposing the properties in your class (public) If you insist on a class, you need to do something like this: plnkr.co/edit/BOaEx8njWV3oBNSVfegM What you are doing, using "return" in the mapping is redundant and that's why you are getting error at least for one reason. When you map, you don't need to use return :)
The main reason i'm using a class here is to be able to instansiate the ticketModel even though not all values are present. Would it be possible to do this using a interface as well?
Yes you can... you can just declare a new object of type TicketModel let ticket = <TicketModel>{} This will of course not hold any properties. But if you really NEED them it's possible, but I see no reason why it should have to have the properties set. Interfaces do not exist on runtime, it's a contract. It helps IDE and programmer, IDE can warn you if you are trying to do something funky with your model. Classes are totally unnecessary if you don't have functions you need in the class. I'm pretty sure 95% of SO users here would give the advice to use interfaces instead ;)
Here's a example of creating properties to your model, so when you initialize a TicketModel, it would have the properties set: stackoverflow.com/a/43788669/6294072
|

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.