Reputation: 157
Say I have a very simple shared service holding a subject:
@Injectable({ providedIn: 'root' })
export class MyService {
private _runTaskSubject = new Subject<string>();
get runTaskSubject$() {
return this._runTaskSubject.asObservable();
}
runTask(name: string) {
this._runTaskSubject.next(string);
}
}
Observers of that runTaskSubject$
will only get notified once runTask
is called.
Now I was thinking to convert this service using signals
, but it seems that not an option as signals
always hold an initial value. So does it makes sense to keep my rxjs Subject
for this use case?
Upvotes: 2
Views: 217
Reputation: 57986
The signals equivalent for the same is as below.
@Injectable({ providedIn: 'root' })
export class MyService {
private _runTaskSignal = signal<string | undefined>(undefined);
get runTaskSignal() {
return this._runTaskSignal.asReadonly();
}
runTask(name: string) {
this._runTaskSignal.set(name);
}
}
We can set the initial value of the signal to be undefined to mimic the subject.
We can use asReadonly
method to convert the signal to a readOnly
signal, the advantage being the readOnly
signal does not have access to set
and update
methods, hence if the signal should be updated, it can be updated only through the runTask
method.
When you read the signal and do not want it to fire on initial load, all you need to do is check that the value is not undefined
and then emit values.
export class SomeComponent {
myService: MyService = inject(MyService);
constructor() {
effect(() => {
// simulate event bus
const runTaskValue = this.myService.runTaskSignal();
if(typeof runTaskValue !== 'undefined') {
// ... some actions happen here!
}
});
}
...
import { Component, Injectable, signal, inject, effect } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
@Injectable({ providedIn: 'root' })
export class MyService {
private _runTaskSignal = signal<string | undefined>(undefined);
get runTaskSignal() {
return this._runTaskSignal.asReadonly();
}
runTask(name: string) {
this._runTaskSignal.set(name);
}
}
@Component({
selector: 'app-root',
template: `
<h1>Hello from {{ myService.runTaskSignal() }}!</h1>
`,
})
export class App {
myService: MyService = inject(MyService);
constructor() {
effect(() => {
// simulate event bus
const runTaskValue = this.myService.runTaskSignal();
if (typeof runTaskValue !== 'undefined') {
console.log('value changed: ', runTaskValue);
}
});
}
ngOnInit() {
setInterval(() => {
this.myService.runTask(`${Math.random()}`);
}, 2000);
}
}
bootstrapApplication(App);
Upvotes: 0