Search code examples
angularrxjsangular2-services

Angular local scope not available inside observable subscription


I have been struggling with this now for a while and tried many solutions.

Inside my subscribe I cant access ChangeDetectorRef or the NgZone to force an update on my scope.

Why doesn't anything work? Is there any other Angular aware way of doing HTTP requests?

The login component

import {ChangeDetectionStrategy, ChangeDetectorRef, Component, NgZone, OnInit} from '@angular/core';
import {LoginService} from './login.service';
import {Observable} from 'rxjs/Observable';

@Component({
    selector: 'app-login',
    templateUrl: './login.component.html',
    styleUrls: ['./login.component.css'],
    providers: [LoginService]
})
export class LoginComponent implements OnInit {
    zone: NgZone;
    username = '';
    password = '';
    showerror = false;
    errormsg = '';
    rs = {};
    results: any;


    constructor(private _loginService: LoginService, private ref: ChangeDetectorRef) {

    }

    refr = function () {
        console.log('refresh');
        console.log(this.errormsg); // is empty even after HTTP call
        this.ref.markForCheck();
        console.log(this.results);
    };

    login = function () {
        console.log(this.username, this.password);

        this._loginService.login(this.username, this.password).subscribe(function (data) {

            console.log('log me in');
            console.log(data); // the correct data is logged here
            this.errormsg = 'Invalid Username and Password'; // the text is never updated
            this.zone.run(); // zone has no method run
            this.ref.markForCheck(); // ref has no method markForCheck
        });

        // this.results = this._loginService.login(this.username, this.password);
        // this.results.subscribe(rs => this.rs = rs);   
    };

    ngOnInit() {

    }

}

The login service

import {Injectable} from '@angular/core';
import {CONFIG} from '../config';
import {Http, Response} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/catch';

const loginUrl: string = CONFIG.apiserv + 'api.login.php';

@Injectable()
export class LoginService {
    private http;
    constructor(http: Http) {
        this.http = http;
    }

    login = function (username, password): Observable<Response> {
        console.log('login clicked');
        let url = new URLSearchParams();
        url.append('username', username);
        url.append('password', password);
        const fullurl = loginUrl + '?' + url.toString();

        return this.http.get(fullurl)
            .map((response: Response) => response.json())
            .do(data => console.log('All: ' + JSON.stringify(data)))
            .catch(this.handleError);
    };
    handleError = function (error: Response) {
        console.log(error);
        return Observable.throw(error.json().error || 'Server error');
    };
}

Solution

  • since you are using this, you should use arrow function:

    this._loginService.login(this.username, this.password).subscribe(data => {
    
            console.log('log me in');
            console.log(data); // the correct data is logged here
            this.errormsg = 'Invalid Username and Password'; // the text is never updated
            this.zone.run(); 
            this.ref.markForCheck(); 
        });