Angular 共享变量值不为';共享';更新时
我正在构建一个Angular应用程序,其中包含以下内容: 非常重要:1共享变量:元素\u id 此变量定义时没有值,存在于名为api.service.ts的服务中 api.service.ts: 此服务包含3个共享函数:1(getMenus)用于从API调用获取菜单内容,第二个(getData)用于从同一API调用获取数据,第三个(change_val)用于从另一个组件中的菜单项调用,并在单击每个菜单项时更改共享变量(element_id)的值当元素_id的值更改时,新值将传递给getData,并从API调用中提取新数据。这并没有发生Angular 共享变量值不为';共享';更新时,angular,Angular,我正在构建一个Angular应用程序,其中包含以下内容: 非常重要:1共享变量:元素\u id 此变量定义时没有值,存在于名为api.service.ts的服务中 api.service.ts: 此服务包含3个共享函数:1(getMenus)用于从API调用获取菜单内容,第二个(getData)用于从同一API调用获取数据,第三个(change_val)用于从另一个组件中的菜单项调用,并在单击每个菜单项时更改共享变量(element_id)的值当元素_id的值更改时,新值将传递给getData,
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class ApiService {
url = 'api address';
element_id; //here is the shared variable
constructor(private http: HttpClient) { }
public getMenus(){
console.log('This ' + this.element_id + ' comes from api.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;
}
}
2部分
导航组件.ts
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[]) => {
this.menus = data;
});
}
public change_val(element_id){
console.log('This ' + element_id + " comes from api.change_val");
this.api.element_id = 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 (via
api)");
console.log(res[this.api.element_id]) ;
}
)};
}
<div *ngFor="let menu of menus; index as id">
<ul>
<li><button (click)="change_val(id)">{{menu['course-lesson-name']}}</button>
</ul>
</div>
<p>{{content['course-lesson-content']}}</p>
- {{菜单['course-lesson-name']}
content.component.html
<div *ngFor="let menu of menus; index as id">
<ul>
<li><button (click)="change_val(id)">{{menu['course-lesson-name']}}</button>
</ul>
</div>
<p>{{content['course-lesson-content']}}</p>
{{content['course-lesson-content']}
问题:
内容从一开始就显示I值元素_id,但在将新值传递给getData时不会更改。元素的id值会根据需要进行更新,并记录到控制台中,但每次按下按钮时,我都需要运行getData
如果我将element_id保留为无值,则内容不会显示,但当单击按钮时,element_值仍将更新。出于某种原因,更新后的元素id值似乎没有从导航组件到服务再到内容组件,这应该在每次单击按钮并更新元素id值时发生。将服务添加到应用程序模块定义的
提供者列表中
@NgModule({
...
providers: [ApiService],
...
})
export class AppModule {}
对GetData的调用在代码中只发生一次。您需要在数据更改时调用它以获取新数据,因为订阅http调用只返回一次值。e、 g:
导航组件:
public change_val(element_id){
this.api.element_id = element_id;
this.api.getData(this.api.element_id).subscribe(res => {
this.api.content = data;
});
}
如果将内容变量移动到服务中,也可以使用在其他组件中引用它来读取值:
服务:
export class ApiService {
url = 'api address';
element_id;
content;
内容模板:
<p>{{api.content['course-lesson-content']}}</p>
{{api.content['course-lesson-content']}
注意:实际上,您应该将服务中的内容变量公开为行为主体,以便您可以从其他组件订阅它以获取最新值。这显示了至少需要如何进行调用以更新它。要使事情变得更简单,您应该有一种常用的组件交互机制:
我喜欢在公共服务中使用BehaviorSubject
,在您的情况下,它将是ApiService
BehaviorSubject
是一种特殊的可观察对象,可以向其所有订户发出新值(使用其next
方法)
这是“新的”ApiService,其中有趣的点是selectedMenu
变量类型BehaviorSubject
,其类型和初始值已设置,以及change\u val
方法,在该方法中,当用户选择菜单选项时,您将发出selectedMenu
变量的新值:
export class ApiService {
url = 'api address';
element_id; //here is the shared variable
selectedMenu = new BehaviorSubject<any>({ name: 'None', id: 0 }); // **IMPORTANT**
menus = [{name: 'Menu 1', id: 1}, {name: 'Menu 2', id: 2}];
constructor(private http: HttpClient) { }
public getMenus(){
console.log('This ' + this.element_id + ' comes from api.getMenus');
return of(this.menus);
//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){
this.element_id = element_id;
let selMen = this.menus.filter(x => x.id == element_id)[0];
this.selectedMenu.next(selMen); // **IMPORTANT**
}
public change_val(element_id) {
console.log("This " + element_id + " comes from api.change_val");
this.api.change_val(element_id); // **IMPORTANT**
}
ContentComponent是“观察者”,您可以在其中订阅ApiService的selectedMenu
BehaviorSubject
:
ngOnInit() {
this.api.selectedMenu.subscribe(res => {
this.content = res;
}); // **IMPORTANT**
}
我几乎完全基于您的代码进行了Stackblitz:JMP,老实说,这不会解决问题。ContentComponent需要以某种方式通知NavComponent中的更改。它只需要通过服务中的内容变量了解新数据。最后一段说,创建一个行为主题,将内容数据更改公开给其他组件。