Angular 可观察订阅内的本地范围不可用

Angular local scope not available inside observable subscription

我现在已经为此苦苦挣扎了一段时间,并尝试了很多解决方案。

在我的订阅中,我无法访问 ChangeDetectorRef 或 NgZone 来强制更新我的范围。

为什么没有任何效果?是否有任何其他 Angular 感知 HTTP 请求的方式?

登录组件

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() {

    }

}

登录服务

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');
    };
}

既然您使用的是 this,您应该使用 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(); 
    });

如果您想将 this 绑定到新创建的作用域,您需要使用 =>.

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

参见:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions

否则,您可以将 this 分配给一个变量,但如果您使用的是 TypeScript 或 ES6,则没有必要。

var that = this;
this._loginService.login(this.username, this.password).subscribe(function (data) {
    that.zone.run();
    ...