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();
...
我现在已经为此苦苦挣扎了一段时间,并尝试了很多解决方案。
在我的订阅中,我无法访问 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();
...