0

Prior to getting the current customer orders I need to return his name, so my related Service class part looks like the following:

Updated:

export class AuthService {

      customerNameUrl = 'customers/name/' + name;
      . . . 
      getCustomerOrders(customerName: string): Observable<CustomerOrder[]> {
          let currentCustomerName = this.getCurrentCustomer(customerName).subscribe(customer => customer.name);
          console.log(currentCustomerName);     <--- Error
          let customerOrders =  this.http.get<CustomerOrder[]>(this.customerOrdersUrl);
          console.log(customerOrders);
          return customerOrders
      }

      getCurrentCustomer(name: string): Observable<Customer> {
        const url = this.customerNameUrl;
        return this.http.get<Customer>(url).pipe(
          tap(_ => this.log(`fetched customer name=${name}`, 'success')),
          catchError(this.handleError<Customer>(`getCustomer name=${name}`))
        );
      }
      . . .
}

But the first console.log shows subscribers instead of the required value. I have tried to add map operator to get only the name from the entity but didn't succeed, maybe added it in the wrong way, any idea?

Sami-L
  • 5,553
  • 18
  • 59
  • 87

1 Answers1

5

The method subscribe returns a Subscriber. That makes sense right? The whole Observable and JS by nature, is mainly async. You fetch data async and you should somehow wait for it, and use a callback to continue with the returned data. See here for the main thread about this.

In your case that would mean that you will have to use something to make the Observables chain. Good thing there are a bunch of operators, there must be one we can use. In this case, the best operator would be mergeMap or concatMap. However, it's unclear to me why you would need the name of the customer, as you are not passing that to the get customer API. Nevertheless, does this solve your query?

getCustomerOrders(customerName: string): Observable<CustomerOrder[]> {
  return this.getCurrentCustomer(customerName).pipe(
    // here you have your customer object, but what do you want to do with it?
    mergeMap((customer) => this.http.get<CustomerOrder[]>(this.customerOrdersUrl))
  );
}

getCurrentCustomer(name: string): Observable<Customer> {
  const url = this.customerNameUrl;

  return this.http.get<Customer>(url).pipe(
    tap(_ => this.log(`fetched customer name=${name}`, 'success')),
    catchError(this.handleError<Customer>(`getCustomer name=${name}`))
  );
}
Poul Kruijt
  • 69,713
  • 12
  • 145
  • 149
  • customer object includes the customer name that I need to show in a mat-select control, my component template includes two selects, one is for customer names and the other shows each customer orders. – Sami-L Feb 29 '20 at 12:47
  • with mergeMap a console.log returns: Observable {_isScalar: false, source: Observable, operator: MergeMapOperator} – Sami-L Feb 29 '20 at 13:06
  • @Sami-L Yes, that's an `Observable`. You can use the `async` pipe inside your template to display it. Considering your comments and question, I strongly advise you to read the answer to a question I linked in my answer – Poul Kruijt Feb 29 '20 at 13:16
  • thanks for the interesting answer link https://stackoverflow.com/a/44154594/1299388 , please kindly consider that I am not using the resulting customer name directly in the template, first I want to use it to make a second request in the same method, which will return the related orders, as the names of the methods are meaningful. giving the customer name to the template is the responsibility of getCurrentCustomer method. – Sami-L Feb 29 '20 at 14:04
  • @Sami-L I understand, just remember, whenever you have a network request, the method doing that request can -never- return the response of the request. This will always be wrapped in a Promise, returned through a callback function or in the form of an Observable. If you want to chain two requests, you use the `mergeMap` operator. This way -inside- the mergeMap, you will have access to the response of the first request, and can pass this along to the second request – Poul Kruijt Feb 29 '20 at 14:12
  • I have added .subscribe(val => {console.log('User Name value: ', val)}) but still could not get it to work. May I ask you please to add the missing part of getCustomerOrders so I can see how mergeMap can be used properly in the second request ? – Sami-L Feb 29 '20 at 14:49