在Angular 5中正确订阅Singleton Service

时间:2018-05-09 06:58:38

标签: angular singleton angular5 angular2-observables

我需要重置一个计时器,它将在每次活动后调用。所以我创建了一个 TimerService 并在其中设置了计时器。

TimerService类:

@Injectable()
export class TimerService {
  timer: Observable<any>;

  constructor() { }

  setTimer(timerVal: number) {
    this.timer = Observable.timer(timerVal);
  }

}

然后我尝试订阅它,一旦计时器失效,它应该发出警告。我把这个逻辑放在AppComponent中,因为我需要在Rootlevel中订阅它。

AppComponent类:

export class AppComponent implements OnInit{
  title = 'DataBox';

  constructor(private timerService: TimerService){}

  ngOnInit() {
    this.timerService.setTimer(3000);
    this.timerService.timer.subscribe(t => {
      alert("hello");
    })
  }
}

现在我尝试从另一个组件更新计时器的值,但它不会影响已经设置的计时器。

AnotherComponent类:

export class AnotherComponent implements OnInit{
  users: Observable<any>;    
  constructor(private listUser: ListUserService, private timerService: TimerService) { }

  ngOnInit() {

  }

  updateTimer() {
    this.timerService.setTimer(5000);
  }

}

我如何订阅timerService并随时更新计时器? 如何创建Singleton服务并订阅计时器? 但它应该只在计时器到期时才发出警报并且只发出一次。 我是Angular的新手,所以请耐心等待。

2 个答案:

答案 0 :(得分:1)

ForestG是正确的,你的基本错误是忽略javaScript引用。

首先,正如ForestG所说,如果它是您正在寻找的简单间隔,请使用javasScript本地间隔和clearInterval方法。

如果您只想运行一个计时器,那么这是您服务中更优雅的解决方案。它通过&#34; takeUntil&#34;创建一个新的区间可观察到条件取消。操作

var xml = '<?xml version="1.0" encoding="UTF-8"?><root><city><ID>1</ID><Name>Kabul</Name><CountryCode>AFG</CountryCode><District>Kabol</District><Population>1780000</Population></city><city><ID>2</ID><Name>Qandahar</Name><CountryCode>AFG</CountryCode><District>Qandahar</District><Population>237500</Population></city><city><ID>3</ID><Name>Herat</Name><CountryCode>AFG</CountryCode><District>Herat</District><Population>186800</Population></city></root>';

var parser = new DOMParser();
// Parse the xml
var parsedXML = parser.parseFromString(xml, 'text/xml');

// Now get the elements
var id = parsedXML.getElementsByTagName('ID');
var Name = parsedXML.getElementsByTagName('Name');
var countryCode = parsedXML.getElementsByTagName('CountryCode');
var district = parsedXML.getElementsByTagName('District');
var population = parsedXML.getElementsByTagName('Population');

// Get the tag names; because getElementsByTagName returns an array like HTMLCollection, we need to loop through the results like we would with an array
for (var i = 0; i < id.length; i++) {
  console.log(id[i].tagName + " " + Name[i].tagName+ " " + countryCode[i].tagName + " "+ district[i].tagName + " "+ population[i].tagName);
}

takeUnitl的优点是我使observable抛出一个&#34;完成&#34;事件,简单&#34; .unsubscribe()&#34;才不是。 这样你就可以添加一个回调来处理前一个计时器。

答案 1 :(得分:0)

问题是,在您的服务中,您不会使用setTimer重置计时器,而是创建一个新计时器。另一个组件的订阅仍然存在于Observable上,它仍然是#34; alive&#34;。您唯一更改的是timer引用,因此任何新的子核心都将订阅新的子核心 - 但旧的订阅仍然存在。

您要做的是,在过度定义时停止第一个计时器,然后设置新计时器。但这只能解决问题的前半部分:你的子语言仍然在监听并等待计时器。所以你必须重新定义你的应用程序逻辑,以及#34;完成&#34;定时器,或者,简单地从它们中取消。

要了解如何停止可观察的计时器,请阅读this question。基本上,您需要先{strong> 每次订阅 unsubscribe(),然后重新订阅。我会用不同的observable(例如&#34; alertWhenNewTimerIsSet()&#34;或其他东西)来实现,然后使用subscription s本身重新订阅新值。

这样的事情: timerservice.ts:

 timer: Observable<any>;
 renewSubscriptionsAlert: new EventEmitter<any>();

 setTimer(timerVal: number) {
    timer.renewSubscriptionsAlert.emit(true);
    this.timer = Observable.timer(timerVal);
  }

并在您的组件中:

 mySubscription: any;

 ngOnInit() {
    this.timerService.setTimer(3000);
    this.mySubscription = this.timerService.timer.subscribe(t => {
      alert("hello");
    });
    this.timerService.renewSubscriptionsAlert(alert => {
      myTimerServiceSubscription.unsubscribe();
       this.mySubscription = this.timerService.timer.subscribe(t => {
      alert("hello");
    });
  }

顺便说一下,如果你只是需要一个计时器,你也可以使用window.setTimeout()方法。