0

I'm writing project using Angular and RxJS. I implemented injectable class that retrieves data from JSON like this:

import {Injectable, Inject} from '@angular/core';
import {Http} from '@angular/http';
import 'rxjs/add/operator/map';

import {Student} from './student.data';

@Injectable()
export class RosterService {
    private students : Student[];
    constructor(@Inject(Http) private http:Http){}

    private getStudents(){
        this.http.get('/JSON/students.json')
            .map(data => data.json().students)
            .subscribe(data => this.students = data);
    }

    public getRoster() {
        this.getStudents();
        return this.students;
    }
}

After I inject RosterService into constructor of AppComponent (including into @Component as provider):

export class AppComponent {
    public students : Student[];
    constructor(private _rosterService : RosterService) {
        this.students = _rosterService.getRoster();
    }
 }

But when I call getRoaster() method, it doesn't wait until getStudents (async get call) is executed. In the result I get undefined value.

How can I deal with it? Thanks for responce.

Ted Romanus
  • 582
  • 2
  • 10
  • 27
  • Extended my question. It isn't the same. – Ted Romanus Jul 20 '16 at 21:30
  • It's exactly the same. You've just added a couple of layers. You want `getRoster` to run `getStudents` synchronously (IOW, complete before returning `this.students`). The duplicate discusses how to structure your code to achieve that. – Heretic Monkey Jul 21 '16 at 17:55

3 Answers3

1

I would use call back function, for example if it is a promise then i would use something like below.

var data;
asyncCall().then((result:any) => {
data = reuslt;
return data;
});

Not sure if that's what your looking for.

Updated:

        @Injectable()
    export class RosterService {
        private students : Student[];
        constructor(@Inject(Http) private http:Http){}

        private getStudents(){
            return this.http.get('/JSON/students.json')
                .map(data => data.json().students)
                .subscribe(data => this.students = data);
        }

        public getRoster() {
           return this.getStudents().then (() =>{
    return this.students;
           });        
         }
       }

And inside your AppComponent

export class AppComponent {
    public students : Student[];
    constructor(private _rosterService : RosterService) {
        this._rosterService.getRoster().then ((data:<T>)=>{
        this.students =data;
     });
    }
 }
Aj1
  • 953
  • 2
  • 15
  • 42
0

It seems to me that you've fundamentally missed a key design pattern in Javascript, which is the callback.

Instead of returning a value from the function, you pass in some code to execute when the function is good and ready.

function doSomething(success) {
    var data = 1;
    // blah blah blah, something happens.
    success(data);
}

function myFunction(data) {
    console.log(data);
}

doSomething(myFunction);

That way, you get to keep the asynchronous nature of the call, which doesn't block the single thread that Javascript has available.

christopher
  • 26,815
  • 5
  • 55
  • 89
0

I'm assuming your asynchronous functions return promises.


First, the logic is kind of weird there.. data is scoped to the function, func can't access data.

Here's what you probably want to do:

function() {
  return func().then(data => data)
}

Except that makes that the same as this:

function() {
  return func()
}

..and in that case you might as well just replace that function with func!

func

(or if func is a property of some other object, () => func().)

EDIT: This new function is an asynchronous function so of course it will return a promise. You'll need to use .then on it later to get the data from it.

Nebula
  • 6,614
  • 4
  • 20
  • 40
  • Sorry for misleading, I incorrectly expressed my question. Adjusted it now. Thanks for your comment and scopes - I dropped it. – Ted Romanus Jul 20 '16 at 21:41