【问题标题】:Angular 6 : Update a value in my component when she change in my serviceAngular 6:当她在我的服务中更改时更新我的​​组件中的值
【发布时间】:2019-04-22 00:14:30
【问题描述】:

我的目标原则上很简单,但我不能把它落实到位:我希望我的一个组件在服务的变量发生变化时更新。

为了更好地解释我的问题,这里是一个例子:

在这里,我有一个增加或减少点数的服务。 当它收到对其功能之一的调用时,它会减少或增加这个点数。 它还说明了这个变量是偶数还是奇数

import { Injectable } from '@angular/core';

@Injectable({
  providedIn: 'root'
})
export class TestService {
  Number: number = 0;
  IsOdd: boolean = false;

  constructor() {}

  IncreaseNumber() {
    this.Number = this.Number + 1;
    this.IsOdd = !this.IsOdd;
  }

  DecreaseNumber() {
    this.Number = this.Number - 1;
    this.IsOdd = !this.IsOdd;
  }
}

*这里,我有我的组件,它需要知道我的数字是偶数还是奇数。

在初始化时,没问题!它知道!

每次我的服务 (test.service.ts) 中的数字发生变化时,我如何确保我的组件 (test.component.ts) 中的值对/导入发生变化?*

import { Component, OnInit } from '@angular/core';
import { TestService } from '../test.service'

@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss']
})

export class TestComponent implements OnInit {

  IsOdd: boolean = false;

  constructor(MyService: TestService) {}

  ngOnInit() {
    this.IsOdd = MyService.IsOdd;
  }

}

我该怎么做?

我的组件是否需要以某种方式 subscribe 为我的服务提供服务? 或者我是否必须使用ngOnInit 之类的功能但要进行更新?

提前致谢

【问题讨论】:

  • 组件“需要知道”的目的是什么?是否需要通知您进行一些额外的处理,还是只需要更新视图?
  • 你怎么知道它不起作用?表示您实施了什么来测试您的服务方法?
  • 您需要在您的服务中使用来自 rxjs 的Subject 并将其公开为您的服务中的 Observable。然后在您的组件中,您需要订阅该服务的 Observable。然后,您需要在服务方法IncreaseNumber 和其他方法中通过主题(如subject.next({val: this.Number, IsOdd : this.IsOdd }))发出一个新值。当您的服务发生任何变化时,您将在组件订阅中获得更新。
  • 首先,感谢主题,我会看看这个。他需要进行附加处理 再次,我把这个例子尽可能简单。我的真实案例更加复杂和混乱。使用一个简单而琐碎的例子可以让人们更容易地回答,而其他人和我有同样问题的人,可以更好地理解答案。我知道这个例子不起作用,因为没有什么让他更新

标签: angular typescript service components


【解决方案1】:

Observable 是一种很好的方法。

另一种简单的方法是在IncreaseNumberDecreaseNumber 方法在TestService 中被调用时发出一个事件。

然后,在 TestComponent 的构造函数中,您可以订阅在 TestService 中创建的事件,然后更新您的 IsOdd 字段(或您希望在组件中更新的任何其他字段)。这种订阅是可能的,因为事件是 observable 的包装器。

像这样: 首先,在您的服务中创建一个事件发射器

    import { Injectable } from '@angular/core';

    @Injectable({
      providedIn: 'root'
    })
    export class TestService {
      Number: number = 0;
      IsOdd: boolean = false;
      EmitIsOdd = new EventEmitter<any>();

      constructor() {}

      IncreaseNumber() {
        this.Number = this.Number + 1;
        this.IsOdd = !this.IsOdd;
        this.EmitIsOdd.emit();
      }

      DecreaseNumber() {
        this.Number = this.Number - 1;
        this.IsOdd = !this.IsOdd;
        this.EmitIsOdd.emit();
      }
    }

然后在你的组件构造函数中订阅事件

    import { Component, OnInit } from '@angular/core';
    import { TestService } from '../test.service'

    @Component({
      selector: 'app-test',
      templateUrl: './test.component.html',
      styleUrls: ['./test.component.scss']
    })

    export class TestComponent implements OnInit {

      IsOdd: boolean = false;

      constructor(MyService: TestService) {
        this.MyService.EmitIsOdd.subscribe(
          () => {
            this.IsOdd = this.MyService.IsOdd;
          }    
        );
      }

      ngOnInit() {
        this.IsOdd = MyService.IsOdd;
      }
    }

你去,简单而有效。

【讨论】:

    【解决方案2】:

    如果这些服务变量是复杂类型(如 Object 或 Array),它会自动更新,因为它们是引用类型。但由于您有 number 和 boolean 类型的 Service 变量,这些变量不会自动更新,因为它们是原始类型,因此按值传递。

    所以你必须使用BehaviorSubjects 并公开它们asObservables。您将通过调用 next 方法来更新这些 BehaviorSubjects 的值。方法如下:

    import { Injectable } from '@angular/core';
    import { BehaviorSubject } from 'rxjs';
    
    @Injectable({
      providedIn: 'root'
    })
    export class TestService {
      private myNumberValue = 0;
      private isOddValue = false;
      private myNumber: BehaviorSubject<number> = new BehaviorSubject<number>(this.myNumberValue);
      private isOdd: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
    
      myNumber$: Observable<number> = this.myNumber.asObservable();
      isOdd$:  Observable<boolean> = this.isOdd.asObservable();
    
      constructor() {}
    
      increaseNumber() {
        this.myNumberValue = this.myNumberValue + 1;
        this.myNumber.next(this.myNumberValue);
        this.isOddValue = !this.isOddValue;
        this.isOdd.next(this.isOddValue);
      }
    
      decreaseNumber() {
        this.myNumberValue = this.myNumberValue - 1;
        this.myNumber.next(this.myNumberValue);
        this.isOddValue = !this.isOddValue;
        this.isOdd.next(this.isOddValue);
      }
    }
    

    现在在您的组件中,您需要做的就是将 subscribe 暴露给服务中的 publicly 暴露的 Observable 值:

    import { Component, OnInit, OnDestroy } from '@angular/core';
    import { TestService } from '../test.service'
    import { Subscription } from 'rxjs';
    
    @Component({
      selector: 'app-test',
      templateUrl: './test.component.html',
      styleUrls: ['./test.component.scss']
    })
    
    export class TestComponent implements OnInit, OnDestroy {
    
      isOdd: boolean;
      subscription: Subscription;
    
      constructor(private testService: TestService) {}
    
      ngOnInit() {
        this.subscription = this.testService.isOdd$.subscribe(isOdd => this.isOdd = isOdd);
      }
    
      ngOnDestroy() {
        this.subscription && this.subscription.unsubscribe();
      }
    
    }
    

    现在,由于您已将 ngOnInit 中的 subscribed 更改为 isOdd$,该 ngOnInit 在组件初始化期间被调用,因此每次服务中的 isOddValue 发生更改时,组件上的 isOdd 都会更新。

    此外,由于这是一个自定义 subscription,它应该分配给组件中的一个属性(subscription),该属性的类型为 Subscription,这是我们从 subscribe 方法中获得的返回值.我们将不得不在ngOnDestroy 中调用unsubscribe 以避免内存泄漏。

    PS:根据Angular's Styleguide,Angular Classes 中的属性和方法名称应采用 lowerCamelCase。

    请使用小写字母来命名属性和方法。

    【讨论】:

    • 也可以使用Subject来实现。并且在ngOndestroy 期间在组件中使用unsubscribe很好避免内存泄漏
    • 谢谢,帮了大忙。而且我认为它会帮助很多其他人,因为这个例子很简单! ^^
    【解决方案3】:

    您可以使用多种解决方案,包括设置 Observable 来订阅更改。这些都是有效的解决方案。

    最简单的解决方案是绑定到模板中的服务而不是值:

    <div> {{ MyService.IsOdd }} </div>
    

    ngOnInit 中,您将布尔 分配给组件的属性。这个值永远不会改变。为了创建数据绑定并响应更改,您必须使用需要 . 的对象绑定对属性的引用,因此,MyService.IsOdd 将在模板中工作。

    https://stackblitz.com/edit/angular-rktij7

    【讨论】:

    • 谢谢,一开始是用的方法。但我不能停止思考“如果我需要在不直接在 html 中使用它的情况下查看它怎么办”。所以我一直在寻找另一种方法^^
    【解决方案4】:

    对于您所说的工作,您应该在 TestComponent 内的服务中增加/减少 number,而不是在其他组件中。

    import { Component, OnInit } from '@angular/core';
    import { TestService } from '../test.service'
    
    @Component({
      selector: 'app-test',
      templateUrl: './test.component.html',
      styleUrls: ['./test.component.scss']
    })
    
    export class TestComponent implements OnInit {
    
      IsOdd: boolean = false;
    
      constructor(MyService: TestService) {}
    
      ngOnInit() {
        this.IsOdd = MyService.IsOdd;
      }
    
      increase() {
        MyService.IncreaseNumber();
      }
    
      decrease() {
        MyService.DecreaseNumber();
      }
    
      getIsOdd() {
        return MyService.IsOdd;
      }
    
    }
    

    【讨论】:

    • 这是一个例子,我试图找出一个简单的例子来解释我的问题。因为随着我的工作,这些事情会变得混乱和复杂^^
    猜你喜欢
    • 2019-05-12
    • 1970-01-01
    • 2018-09-28
    • 2019-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多