0

I am trying to make an http request inside a Promise function. I get the this.http.post is undefined error... I know that I somehow have to access this some other way but I did not understand how to do it.

Anyone willing to help me out?

doUpload(files: Array<File>): Promise<Array<UploadResult>> {
    console.log(files);
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        let result: Array<UploadResult> = [];
        for (let file of files) {
          this.http
            .post(this.APIURL + "/image/upload/markdown", file)
            .subscribe((data) => {
              console.log(data);
            });
          result.push({
            name: file.name,
            url: `https://avatars3.githubusercontent.com/${file.name}`,
            isImg: file.type.indexOf("image") !== -1,
          });
        }
        resolve(result);
      }, 3000);
    });
  }

The error:

> TypeError: undefined is not an object (evaluating 'this.http.post')  
> (anonyme Funktion) — sensor-edit.component.ts:308  
> onInvokeTask — core.js:39680  
> runTask — zone-evergreen.js:168  
> invokeTask — zone-evergreen.js:465  
> timer — zone-evergreen.js:2650

The constructor:

constructor(
    private fb: FormBuilder,
    private route: ActivatedRoute,
    private api: ApiService,
    private _routerService: Router,
    private errorService: ErrorModalService,
    private sanitizer: DomSanitizer,
    private http: HttpClient
  ) {}

And doUpload is called in my Html like this:

<div class="container well come-space">
          <md-editor formControlName="markdown" name="Content" [height]="'400px'" [upload]="doUpload">
          </md-editor>
</div>
cypherduck
  • 61
  • 7
  • 2
    Can you add the error stack? Arrow function will automatically point to the correct lexical scope. It should work fine. – Apoorva Chikara Oct 28 '21 at 12:27
  • In addition, log `this.http`. It seems it points to some object, but not to the one you expect. – Lesiak Oct 28 '21 at 12:32
  • Sure. Just edited the question. When I log `this.http` it says `undefined`.. – cypherduck Oct 28 '21 at 12:34
  • Please show us the `constructor` of your component as well as the module declaration where this component is being declared in. – Philipp Meissner Oct 28 '21 at 12:41
  • Does this answer your question? [How to access the correct \`this\` inside a callback](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Heretic Monkey Oct 28 '21 at 12:43
  • Also, [Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference](http://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Heretic Monkey Oct 28 '21 at 12:45
  • 1
    Can you show the piece of code where `doUpload` is called ? – Arnaud Denoyelle Oct 28 '21 at 12:46
  • Wow, the way you pass `doUpload` is weird. You actually pass the function as an input ? Can you try to pass `doUpload.bind(this)` instead ? (make an intermediate variable in the ts if necessary) – Arnaud Denoyelle Oct 28 '21 at 12:49

1 Answers1

0

TBH, I don't see the use of converting the Observable to Promise here. In fact at the moment you're creating multiple subscriptions that could be left open. Instead I'd use the RxJS forkJoin to trigger multiple observables in parallel within a single subscription.

Try the following

import { forkJoin, Observable } from 'rxjs';
import { map } from 'rxjs/operators';

doUpload(files: Array<File>): Observable<Array<UploadResult>> {
  return forkJoin(                                  // <-- RxJS `forkJoin` function
    files.map((file: any) =>                        // <-- `Array#map` function
      this.http.post(
        this.APIURL + "/image/upload/markdown", 
        file
      ).pipe(
        map((data: any) => ({                       // <-- RxJS `map` operator
          name: file.name,
          url: `https://avatars3.githubusercontent.com/${file.name}`,
          isImg: file.type.indexOf("image") !== -1,
        }))
      )
    )
  );
}

Then you could subscribe to it

this.doUpload(files).subscribe({
  next: (response) => console.log(response),
  error: (error) => console.log(error)
});

Update

As told in the comments, my solution cannot be used in combination with <md-editor>'s @Input() upload variable. Use your own doUpload() implementation with the following snippet your component's constructor.

constructor() {
  this.doUpload = this.doUpload.bind(this);
}

Taken from ngx-markdown-editor's docs.

ruth
  • 29,535
  • 4
  • 30
  • 57
  • While your answer holds a true statement, it does not answer the actual question. – Philipp Meissner Oct 28 '21 at 12:42
  • Thanks.. but now I get this error `undefined is not a function (near '...files.map...')` – cypherduck Oct 28 '21 at 12:43
  • I didn't realize you were passing the `doUpload()` function as an `@Input` to the ``. In this case my solution wouldn't apply. Try doing `this.doUpload = this.doUpload.bind(this);` inside the component's constructor with your initial implementation of the `doUpload()` function. Taken from their [docs](https://www.npmjs.com/package/ngx-markdown-editor). – ruth Oct 28 '21 at 13:13