0

My task is to create a method in contest.service.ts that will get data (contests) from server, do the necessary manipulations with it and return the result.

contest.service.ts:

    getContests() {
        let id = IDs.contests.getAll;
        let body = { 
            ...
        };

        let result;

        this.wsservice.send(id, body);

        this.wsservice.on<any>(IDs.contests.getAll)
            .subscribe((msg) => {
                console.log('msg', msg);
                if (!msg['code']) {
                    result = msg;
                    console.log('contests msg', result);
                    this.contests = result.map(contest => {
                        return new Contest({
                            id: contest.id,
                            name: contest.name || "Нет названия",
                            description: contest.description,
                            contestTasks: contest.tasks || []
                        });
                    });
                }
                else {
                    result = "Error";
                }
            });

        return result;
    }

I need to wait until subscription to this.wsservice.on(IDs.contests.getAll) finishes and then return the result from it. Methods from websocket.service.ts:

    public send(eventId: any, data: any = {}): void {
        console.log('SEND');
        let that = this;
        if (eventId && this.isConnected && this.websocket$) {
            data['id'] = eventId;
            this.websocket$.next(data);
        } else {
            setTimeout(function() {
                that.send(eventId, data);
            }, 500);
            console.log('Still connecting, resending messsage...');
        }
    }

    public on<T>(eventId: any): Observable<T> {
        console.log(eventId);
        if (eventId) {
            return this.wsMessages$.pipe(
                filter((message: IWsMessage<T>) => message.id === eventId),
                map((message: IWsMessage<T>) => message.result ? message.result : message.error)
            );
        }
    }
quid
  • 67
  • 1
  • 9
  • 1
    This has been answered several times before. Data from a Promise (and an Observable) is asynchronous. It cannot be returned synchronously like you're attempting. Please read [this](https://stackoverflow.com/q/14220321/6513921) post in it's entirety to understand what is asynchronous data and how to use it. – ruth Jan 07 '21 at 16:10
  • @MichaelD, do you send a newbie in Angular to an answer that has hundreds of pages???. – Eliseo Jan 07 '21 at 18:03
  • @Quid, your services shouls return observables and you subscribe in the component. If you want return an object transform the response and use `pipe(switchMap(res=>{....return of(your object)}` – Eliseo Jan 07 '21 at 18:05
  • @Eliseo: Perhaps I should've been more clear. I was referring to the question and the self-answer by the OP. It is the quickest and self-sufficient explanation of async paradigm I've seen in SO. – ruth Jan 08 '21 at 08:32

1 Answers1

1

Improving my comment.

You should return an observable. You can use

getContests() {
   ....
   return this.wsservice.on<any>(IDs.contests.getAll).pipe(
    //we don't want the response else
    switchMap(msg)=>{
      ..do something with the msg..
      //create an object
      const contest= new Contest({
                 ...});
       //we need return an observable, we use rxjs operator 'of'
       return of(contest)
   }
   )

Or use map

getContests() {
   ....
   return this.wsservice.on<any>(IDs.contests.getAll).pipe(
    //we are going to transform the response
    map(msg)=>{
      ..do something with the msg..
      //create an object
      const contest= new Contest({
                 ...});
       return contest; //<--see that return simple the object
   }
   )

See that return an observable, so in you component subscribe

this.service.getContests().subscribe(res=>{
   //here you has the object contest
   console.log(res)
})
Eliseo
  • 50,109
  • 4
  • 29
  • 67