Значение совместно используемой переменной не является «общим» при обновлении - PullRequest
2 голосов
/ 03 марта 2020

Я создаю Angular приложение, которое содержит следующее:

Очень важно: 1 общая переменная: element_id Эта переменная определена без значения и находится в службе api.service. ts

api.service.ts: Этот сервис содержит 3 общие функции: 1 (getMenus) для получения содержимого меню из вызова API, секунду (getData) для получения данные из того же вызова API и третьего (change_val), который вызывается из пунктов меню в другом компоненте и изменяет значение общей переменной (element_id) при щелчке каждого элемента меню. Когда значение element_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 компонента

nav.component.ts

  1. это содержит лог c для создания меню из вызова REST API
  2. также содержит функцию shred publi c для изменения значения общей переменной (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[]) => {
    this.menus = data;
    });
    }
    
    public change_val(element_id){
    console.log('This ' + element_id + " comes from api.change_val");
    this.api.element_id = element_id;
    
    }
    }
    

content.component.ts

  1. содержит логи c для отображения содержимого из вызова API на основе значения 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>

content.component. html

<p>{{content['course-lesson-content']}}</p>

Проблемы:

Содержимое показывает, если я ценю element_id с самого начала, но не изменяется, когда новые значения передаются в getData. Значение element_id обновляется по мере необходимости и регистрируется в консоли, но мне нужно, чтобы getData запускался каждый раз, когда кнопка.

Если я оставлю element_id без значения, содержимое не будет отображаться, но element_values ​​будет по-прежнему обновлять при нажатии кнопок. По какой-то причине обновленное значение element_id, по-видимому, не достигает перехода от компонента nav к службе и к компоненту содержимого, это должно происходить при каждом нажатии кнопки и обновлении значения element_id.

Ответы [ 3 ]

1 голос
/ 04 марта 2020

Чтобы упростить задачу, вы должны использовать один из обычно используемых механизмов взаимодействия компонентов: https://angular.io/guide/component-interaction

Мне нравится использовать BehaviorSubject в общей службе, в в вашем случае это будет ApiService. BehaviorSubject - это особый вид наблюдаемой, который может выдавать новые значения (с помощью next метода) всем своим подписчикам.

Это «новый» ApiService , где интересные моменты переменная selectedMenu типа BehaviorSubject с указанием ее типа и начального значения и метод change_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**
  }

В вашем NavComponent вы вызываете метод ApiService «change_val», когда пользователь выбирает пункт меню:

  public change_val(element_id) {
    console.log("This " + element_id + " comes from api.change_val");
    this.api.change_val(element_id); // **IMPORTANT**
  }

ContentComponent является «Наблюдатель», где вы подписываетесь на selectedMenu BehaviorSubject ApiService:

  ngOnInit() {
    this.api.selectedMenu.subscribe(res => {
      this.content = res;
    }); // **IMPORTANT**
  }

Я почти полностью создал Stackblitz на основе вашего кода: https://stackblitz.com/edit/angular-j2wfjp

0 голосов
/ 03 марта 2020

Вызов GetData происходит только один раз в вашем коде ngOnInit. Вам нужно будет вызывать его всякий раз, когда данные изменяются, чтобы получить новые данные, так как подписка на вызов HTTP возвращает значение только один раз. Например:

nav.component:

    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>

Обратите внимание, что на самом деле вы должны выставить переменную содержимого из службы как, например, BehaviourSubject, чтобы вы могли подписаться на нее из другого компонента для получить последнее значение. Это показывает, как должен быть выполнен вызов, чтобы хотя бы обновить его.

0 голосов
/ 03 марта 2020

Добавьте сервис в список providers определения вашего прикладного модуля.

@NgModule({
...
providers: [ApiService],
...
})
export class AppModule {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...