15

I've a service with an authenticate function -

authenticate(username: string, password: string) {
        let ret;
        let packet = JSON.stringify({
            username: username,
            password: password
        });

        let headers = new Headers();
        headers.append('Content-Type', 'application/json');

        this.http.post('http://localhost:5000/api/authenticate/', packet, {
            headers: headers
        })
        .map(res => res.json())
        .subscribe(
            data => { 
                // put return data into ret
                ret = data.token;
            },
            err => console.log(err),
            () => {
                // this works!
                console.log(ret);
            }
        );

        // get's returned before I put data into it
        return ret;
    }

So if I call the authenticate function console.log(authenticate('a', 'b'));, it logs undefined since the ret variable is returned before the subscribe function can put the data into it. How can I return the http response data from authenticate function? I've never done any reactive programming with RxJS before and that's what angular 2 seems to be using.

PS. Is there any decent CSP solution for javascript like go channels or core.async?

4
  • 1
    That's not really how async or RxJs works; you don't return data from asynchronous functions. Commented Mar 31, 2016 at 20:14
  • that much i figured since subscribe gets executed after I return the ret variable. any ideas on how I can return data when I'm dealing with RxJS? Commented Mar 31, 2016 at 20:18
  • you could create another method, say this.authenticateFinished(ret) { console.log(ret); // and anything else } and then call this from data => {} Commented Mar 31, 2016 at 20:19
  • Well, subscribe is executed before you return, but it's async. I don't know what the AngJS "way" is, but you'd either need a callback, or an observer, or whatever event stream mechanism RxJS uses. Commented Mar 31, 2016 at 20:20

2 Answers 2

12

I used Observables and Observers to build my solution. Since @Injectable creates a singleton class, I declared an Observable inside of it which I then exposed to my component. When I put any data into it, all subscribers get notified of the event. Warning: if you use this with zone.js 0.5, it won't work. Works with 0.6.

import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import 'rxjs/add/operator/share';
import 'rxjs/add/operator/map';
import 'rxjs/Rx';


@Injectable()
export class AuthService {
    // expose to component
    notification$: Observable<Notification>;
    private observer: Observer<Notification>;

    ....

    constructor(private http: Http) {
        this.notification$ = new Observable(observer => this.observer = observer).share();
    }

    authenticate({username, password}) {
        let packet = JSON.stringify({
            username: username,
            password: password
        });

        let headers = new Headers();
        headers.append('Content-Type', 'application/json');

        this.http.post(`${this.baseUri}/authenticate/`, packet, {
            headers: headers
        })
        .map(res => res.json())
        .subscribe(
            data => {
                if (data.success && data.token) {
                    this.saveJwt(data.token);
                } else {
                    this.deleteJwt();
                }
                // put data into observavle 
                this.observer.next({
                    message: data.message,
                    type: data.success
                });
            },
            err => {
                // put data into observavle  
                this.observer.next({
                    message: 'Error connecting to server',
                    type: false
                })
            },
            () => {}
        );
    }
}


export class AuthComponent implements OnInit {
    observable: Observable<Notification>;

    ...

    ngOnInit() {
        // subscribe to the observable
        this.observable = this.authService.notification$;
        this.observable.subscribe(
            data => {
                ...
            }
        )
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

what is notifaction in "private observer: Observer<Notification>" ??what can i pass to Observer?
just replace <Notification> with <any>
4

You need to return the observable corresponding your request directly:

authenticate(username: string, password: string) {
  let ret;
  let packet = JSON.stringify({
    username: username,
    password: password
  });

  let headers = new Headers();
  headers.append('Content-Type', 'application/json');

  return this.http.post('http://localhost:5000/api/authenticate/', packet, {
    headers: headers
  })
  .map(res => res.json());
}

And the caller of the authenticate method must subscribe on it to receive the result:

this.service.authenticate('username', 'password').subscribe(
  (result) => {
    console.log('Result received');
    console.log(result);
  }
);

1 Comment

Thanks for that. However, I wanted all the logic to go inside of a service instead of a component. I figured it out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.