Angular 共享变量值不为';共享';更新时

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,

我正在构建一个Angular应用程序,其中包含以下内容:

非常重要:1共享变量:元素\u id 此变量定义时没有值,存在于名为api.service.ts的服务中

api.service.ts: 此服务包含3个共享函数:1(getMenus)用于从API调用获取菜单内容,第二个(getData)用于从同一API调用获取数据,第三个(change_val)用于从另一个组件中的菜单项调用,并在单击每个菜单项时更改共享变量(element_id)的值当元素_id的值更改时,新值将传递给getData,并从API调用中提取新数据。这并没有发生

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

  • 它包含从RESTAPI调用构造菜单的逻辑
  • 它还包含一个用于更改共享变量(element_id)值的分解公共函数:

  • content.component.ts

  • 它包含基于元素_id的值显示API调用内容的逻辑:

    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]) ;
      } 
      )};
      }
    
  • nav.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>
    
    
    
    • {{菜单['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中的更改。它只需要通过服务中的内容变量了解新数据。最后一段说,创建一个行为主题,将内容数据更改公开给其他组件。