angular - NgOnInit 中的变量未更新
问题描述
我正在构建一个使用两个组件的应用程序:
- 导航
- 内容
它还使用一个共享服务进行 API 调用和存储共享函数:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ApiService {
url = 'api address';
element_id;
constructor(private http: HttpClient) { }
public getMenus(){
return this.http.get(this.url);
}
public getData(element_id){
console.log('This ' + element_id + ' comes from api.getData')
return this.http.get(this.url);
}
public change_val(element_id){
console.log('This ' + element_id + " comes from api.change_val");
this.element_id = element_id;
}
}
导航组件
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ApiService } from '../api.service';
@Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.css']
})
export class NavComponent implements OnInit {
menus;
constructor(private api: ApiService,){}
ngOnInit(){
this.api.getMenus().subscribe((data: any[]) => {
//console.log(data);
this.menus = data;
});
}
public change_val(element_id){
console.log("This " + element_id + " comes from nav.component")
this.api.change_val(element_id)
this.api.getData(element_id)
}
}
内容组件
import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { ApiService } from '../api.service';
@Component({
selector: 'app-content',
templateUrl: './content.component.html',
styleUrls: ['./content.component.css']
})
export class ContentComponent implements OnInit {
content;
constructor(private api: ApiService) { }
ngOnInit(){
this.api.getData(this.api.element_id).subscribe(res => {
this.content = res[this.api.element_id];
console.log("This " + this.api.element_id + " is coming from content getData")
});
}
}
在上面的 content.component.ts 中,console.log 中的字符串在应用第一次运行时是未定义的。
使用 nav.component.html 中的以下接口,我可以将相同的 id 值传递给所有函数,如下所示:
<div *ngFor="let menu of menus; index as id">
<ul>
<li><button (click)="change_val(id)">{{menu['course-lesson-name']}}</button></li>
</ul>
</div>
经过检查,可以看到共享变量 element_id 在服务中没有任何值,并且应该在用户单击视图中的每个按钮时更新。当应用程序首次打开或刷新时,element_id 未定义(不知道如何解决此问题),但只要我单击任何按钮,导航组件中的 element_id 和服务就会更新,但不会在内容组件中更新。
ngOnInit 是否会运行一次,然后在应用程序刷新之前不再运行?每次 element_id 更改时,我都需要更新以下内容。
this.api.getData(this.api.element_id).subscribe(res => {
this.content = res[this.api.element_id];
console.log("This " + this.api.element_id + " is coming from content getData")
解决方案
ngOnInit 只运行一次,在组件实例化时,您要在此处使用的是通知感兴趣的组件更改的主题,像这样设置您的服务:
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
// replay subjects cache values and replay them to new subscribers, good for timing problems
import { ReplaySubject } from 'rxjs'
@Injectable({
providedIn: 'root'
})
export class ApiService {
url = 'api address';
private elementIdSource = new ReplaySubject(1); // private subject
elementId$ = this.elementIdSource.asObservable(); // public observable
constructor(private http: HttpClient) { }
public getMenus(){
return this.http.get(this.url);
}
public getData(element_id){
console.log('This ' + element_id + ' comes from api.getData')
return this.http.get(this.url);
}
public change_val(element_id){
console.log('This ' + element_id + " comes from api.change_val");
// next on source to notify consumers
this.elementIdSource.next(element_id)
}
}
然后在您的组件中,您订阅以获取更改:
// operators need to be imported
// switchMap takes an observable value and switches into a new observable based on it
// map takes an observable value and transforms it
import {switchMap, map} from 'rxjs/operators'
ngOnInit(){
// subscribe to elementId$ changes (save your subscription!)
this.idSub = this.api.elementId$.pipe(
//switch into data fetch and map into the proper key
switchMap(elementId => this.api.getData(elementId).pipe(map(res => res[elementId])))
).subscribe(data => {
this.content = data;
console.log(data, " is coming from content getData")
});
}
ngOnDestroy() {
this.idSub.unsubscribe(); // clean up subscription to avoid memory leak!
}
现在您的组件将始终知道什么时候发生了变化。共享服务模型基本上都是采用这种模型。