首页 > 解决方案 > Angular Observable 不会实时显示我的值

问题描述

我有 2 个组件(菜单和标题)和一个服务。我想要做的是,当他们从菜单中选择一个项目时,菜单将文本发送到服务,服务将其发送到标题并更改它。我已经设法将它发送到服务,但我不知道为什么在带有 Observable 的标头中它没有更新。

服务:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import 'rxjs/add/observable/from'; 
import { of } from 'rxjs';

@Injectable()
export class passVarHelper{

    currentIndex: string;
    constructor(

    ){
        this.currentIndex = "Title";
    }


    getIndex(): Observable <string> {
        return of(this.currentIndex);
    }

    changeIndex(index:string){
        this.currentIndex = index;
        console.log(this.currentIndex);
    }



}

标题:

import { Component, OnInit } from '@angular/core';
import { passVarHelper } from 'src/app/helpers/passVar.helper';

@Component({
  selector: 'app-headerpage',
  templateUrl: './headerpage.component.html',
  styleUrls: ['./headerpage.component.css'],
  providers: [passVarHelper]
})
export class HeaderpageComponent implements OnInit {
  index:string;
  constructor(private _passVarHelper: passVarHelper) {

   }

  ngOnInit() {
    this.loadIndex();
  }

  loadIndex(){
    this._passVarHelper.getIndex().subscribe(
      response  => {
        if(response){
          console.log(response);
          this.index = response;
        }
      },
      error => {
        console.log(<any>error);
      }
    );
  }

}

菜单:

import { Component, OnInit, Input, OnDestroy } from '@angular/core';
import { passVarHelper } from 'src/app/helpers/passVar.helper';

@Component({
  selector: 'app-asidenavbar',
  templateUrl: './asidenavbar.component.html',
  styleUrls: ['./asidenavbar.component.css'],
  providers: [passVarHelper]
})
export class AsidenavbarComponent implements OnInit {


constructor(private _passVarHelper: passVarHelper) { 
  }

  ngOnInit() {

  }


  menuClick(){
    var indexMenu = document.getElementById('menu').innerHTML;
    this._passVarHelper.changeIndex(indexMenu);

  }


}

标题 HTML

<div class="content-header">
  <div class="container-fluid">
    <div class="row mb-2">
      <div class="col-sm-6">
        <h1 class="m-0 text-dark">{{index}}</h1>
      </div>
      <div class="col-sm-6">
        <ol class="breadcrumb float-sm-right">
          <li class="breadcrumb-item"><a href="#">Volver</a></li>
        </ol>
      </div>
    </div>
  </div>
</div>

标签: angularangular6

解决方案


Observable.of是一次事件,根据文档:

创建一个 Observable,它发出一些您指定为参数的值,一个接一个地发出,然后发出一个完整的通知。

关于完整通知的最后一部分很重要,因为一旦完成(第一次执行)它就会发出complete事件并且不再发出。您需要做的是使用SubjectorBehaviorSubject来获得源源不断的事件流。

尝试这样的事情:

@Injectable()
  export class PassVarHelper {
  currentIndex: string;
  currentIndexObs: BehaviorSubject<string>;

  constructor() {
    this.currentIndex = "Title";
    this.currentIndexObs = new BehaviorSubject<string>(this.currentIndex);
  }

  changeIndex(index: string) {
    this.currentIndex = index;
    this.currentIndexObs.next(this.currentIndex);
  }
}

然后loadIndex方法:

loadIndex() {
  this._passVarHelper.currentIndexObs.subscribe(
    response => {
      if (response) {
        console.log(response);
        this.index = response;
      }
    },
    error => {
      console.log(<any>error);
    }
  );
}

这是演示此行为的stackblitz示例。

编辑:好的,我知道问题出在哪里......它在providers数组中,您不能在组件中提供服务,您必须在它们上方的组件中提供它(如或header​​)。如果您在这两个组件中提供服务,您将获得不同的服务实例,而您想要实现的目标将不起作用。menuapp.moduleapp.component

因此,passVarHelper在其中一个(如果另一个是第一个的孩子)或app.module.ts providers数组中提供(检查我提供的stackblitz示例,我在 中提供了服务app.module.ts)并且在那个地方提供(为了获得相同的实例) .

嗯,Angular 有一个叫做provider scope的东西。例如,看一下这个定义:

当您在根级别提供服务时,Angular 会创建一个共享的服务实例并注入到任何需要它的类中。

这意味着当您在根级别提供服务时,无论您使用 DI 注入它(例如在构造函数中注入它时),您都将获得该服务的单个实例。

但是,您也可以在任何其他组件中提供服务。通过在组件中提供服务,您实际上将服务仅限于该组件和该组件内的组件。本质上,通过在组件中提供服务,当您将其注入该组件时,您将获得该服务的一个新实例(并且它的所有子代都将拥有该实例,除非它们自己提供该服务)。

因此,服务的单个实例用于组件及其所有子组件,但如果在任何子组件中提供,则该子组件及其所有子组件将获得新实例。

希望这使它更清楚一点。

有趣的阅​​读材料:


推荐阅读