3

New to Angular and promises, but I've realized I've done this a lot:

this.myService.createFoo(data).subscribe(
  (result: any) => {
    resolve({success: true, data: result});
  },
  err => {
    resolve({success: false, message: err});
  });

this.myService.updateFoo(data).subscribe(
  (result: any) => {
    resolve({success: true, data: result});
  },
  err => {
    resolve({success: false, message: err});
  });

How would I rewrite the completion closure for my subscribe method so that I don't repeat code like this?. Thanks!

Aravind
  • 40,391
  • 16
  • 91
  • 110
7ball
  • 2,183
  • 4
  • 26
  • 61
  • You could try using `async` and `await` but I'm not sure how easily that will be to slip into what you're doing (not super familiar with angular or subscribe) https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function – Dr_Derp Aug 04 '17 at 18:06
  • 1
    How are `resolve` and `reject` defined? Are those coming from the `Promise` constructor, like `return new Promise((resolve, reject) => {...})`, or somewhere else? Might help if you posted a slightly more inclusive code sample. – Lukas S. Aug 04 '17 at 18:09
  • Yes, it's just like the normal `new promise ....` like you said. – 7ball Aug 04 '17 at 18:16

3 Answers3

2

One approach would be to extract your callbacks into generic functions and just pass those:

const successHandler = (data: any) => resolve({success: true, data });
const errorHandler = (message) => resolve({success: false, message });

this.myService.createFoo(data).subscribe(successHandler, errorHandler);
this.myService.updateFoo(data).subscribe(successHandler, errorHandler);

If you want to define these outside of the scope of the Promise (which I assume the code you posted is inside of), you could curry the handlers:

some-util-library.js

const handlers = resolve => ({
    success: (data: any) => resolve({success: true, data }),
    error: (message) => resolve({success: false, message })
});
export { handlers };

otherfile.js

import { handlers } from './some-util-library.js';
... other code
const { success, error } = handlers(resolve);
this.myService.createFoo(data).subscribe(success, error);
this.myService.updateFoo(data).subscribe(success, error);
Rob M.
  • 35,491
  • 6
  • 51
  • 50
  • Can you just use `resolve` like that, or do you have to specify it as a parameter? – Wolfie Aug 04 '17 at 18:07
  • Good question, it wasn't obvious in the code OP posted where `resolve` was coming from, so I assumed it was available from a parent scope or as a global – Rob M. Aug 04 '17 at 18:08
0

I'm assuming you're trying to return a promise, and that the code you posted is contained in a method that looks something like this:

create(): Promise<any> {
  const data = 'whatever';
  return new Promise<any>((resolve, reject) => {
    this.myService.createFoo(data).subscribe(
      (result: any) => {
        resolve({ success: true, data: result });
      },
      err => {
        resolve({ success: false, message: err });
      });
  });
}

If that's the case, rather than manually creating a promise, you can turn your Observable into a promise using the toPromise operator. You will need to import it first if you haven't already:

import 'rxjs/add/operator/toPromise';

Then, combining it with async and await, you can transform your code as follows:

async create(): Promise<any> {
  const data = 'whatever';
  try {
    const result = await this.myService.createFoo(data).toPromise();
    return { success: true, data: result }
  } catch (err) {
    return { success: false, message: err };
  }
}
Lukas S.
  • 5,698
  • 5
  • 35
  • 50
0

This seems like the perfect use case for Angular HttpClient Interceptors

Jaime
  • 488
  • 3
  • 8