Svelte with rxjs Observable in object property - rxjs

I'm trying to use an rxjs Observable in Svelte rendering. I understand I can do that :
<span>{$myObservable}</span>
but what if myObservable is inside an object:
<span>{$myObject.myObservable}</span>
the "$" now gives me the error :
(Stores must be declared at the top level of the component (this may
change in a future version of Svelte)
Anyone has a workaround for that?
Example here :
https://stackblitz.com/edit/testsveltebindrxjs?file=src%2FApp.svelte&terminal=dev

Related

Angular11 using function in *ngIf in the template is getting invoked many times. how to avoid

I have the following code. I am using a function in *ngIf and it is being called many times. How to fix this? Can anyone help me with this?
<button
type="button"
class="button primary"
*ngIf="canComplete() | async"
(click)="complete()"
>
<span *ngIf="!userCanCompleteAudit">Complete assigned sections</span>
<span *ngIf="userCanCompleteAudit">Complete audit</span>
</button>
canComplete() {
return this.service.sub$.pipe(
takeUntil(this.cancel$),
take(1),
map(
(responses) =>
responses.every((r) => r.valid)
)
);
}
By design, canComplete() will indeed get invoked many times. More precisely, it will get invoked for every change detection cycle. So the question now is, what is a change detection cycle, how does it relate to your problem, and how can we build a solution with knowledge about it?
Introduction to Change Detection
Whenever a user interacts with your app, be it by clicking any buttons on a page, or triggering an HTTP request for example, Angular by default, has to re-evaluate all template expressions in your component template (i.e. your HTML code). Or as we say it, a change detection cycle is triggered.
In your case, Angular will re-evaluate the following template expressions:
the value of canComplete() | async (1st template expression),
of !userCanCompleteAudit (2nd template expression),
and of userCanCompleteAudit (3rd template expression).
Why does Angular have to re-evaluate the values of these template expressions, you ask? So that when Angular determines that an expression's value has changed, Angular will then update the template view (basically the DOM) accordingly.
For example, if your 2nd template expression !userCanCompleteAudit evaluates from previously true to now false, Angular will then remove <span>Complete assigned sections</span> from the DOM, as per your logic. On the other hand, if Angular finds out that !userCanComplateAudit did not change after checking said expression's current value, Angular leaves that span element alone and keeps it displayed.
When is an Expression Considered "Changed"?
How does Angular decide when a template expression has "changed"? Simple. By default, Angular:
gets the template expression's old value,
evaluates its new value,
then performs a === against the expression's old and new values.
If they are not strictly equal, Angular marks the template expression as changed, and updates the template view accordingly.
Why Methods in Template Expression Execute Multiple Times
At this point, we now know that for every change detection cycle (e.g. user interactions), template expressions get re-evaluated as part of Angular's change detection mechanism. And there lies the problem.
For your 2nd template expression canComplete() | async, this means that:
For every change detection cycle, canComplete() | async is evaluated.
Every time canComplete() | async is evaluated, canComplete() method is called. (This in particular is the issue you're seeing.)
Every time canComplete() is called, a new observable object is returned from this.service.sub$.pipe(...).
Every time an observable is returned from canComplate(), a new subscription instance is made in the template via the async pipe.
For every subscriptions made, the pipeline is run (calling responses.every((r) => r.valid) every time).
How to Prevent Method From Executing Multiple Times
The answer to this is a case-to-case basis. Depending on the context of your code, you might have to apply at least one of the following:
Setting your component's change detection strategy to ChangeDetectionStrategy.OnPush.
Refactoring your method (that returns an observable) into a observable variable.
Subscribing from the controller instead of the template.
Most likely in your case, and without diving too much into details, your best bet is to apply bullet 3: subscribe from your component's controller.
// your component controller
#Component(...)
export class MyComponent implements OnInit {
...
canComplete = false;
ngOnInit() {
this.service.sub$.pipe(
take(1),
map((responses) => responses.every((r) => r.valid)),
takeUntil(this.cancel$)
)
.subscribe((canComplete) => this.canComplete = canComplete);
}
}
<button *ngIf="canComplete" class="...">...</button>

When should we use the RxJS tap operator?

I do not understand from the docs. Could anyone explain it to me?
Most of the operators are working in streamed sequence, for example:
source$.pipe(
map((a: string) => changeAndReturnArray(a)),
filter((b: string[]) => giveMeOnlySymbolsThatAreAfterNInAlphabet(b)),
switchMap((c: string[]) => putToSomeObservable(c))
....
);
In that example you are not 'breaking' the stream, or jumping outside of it to do some external action.
Jumping outside of stream is possible with 'tap' operator, where you can:
call functions that will cause some side effect, that might be visible to end user (for example - display dialog, show snackbar, redirect to different route (but in my opinion it's not recommended to use tap in that way))
dispatch actions for store (if you are using any - for example ngrx store)
debug you're code -> console.log()
anything what can be considered as 'side effect' for your stream.
My personal opinion - use 'tap' only if you can't find any better solution. Jumping outside of stream and calling some side effect can be double edged sword, especially when your dealing with some bigger application. Side effect are always harder to maintain, and you can finish with application that is doing magic stuff without any reason.
You can use it to perform a side effect for example. Or you can use it to see what's the current value that is being passed around without affecting/modifying the Observable. So something like a console.log() but inside the stream.
Decalration
public tap(nextOrObserver: Observer | function, error: function, complete: function): Observable
tap is replacement of do operator which returns observable identical to your source observable. for each value emitted, perform a side-effect. it has 3 optional parameters.
nextOrObserver: A normal Observable object to perform side effect.
error: Callback for errors in source Observable.
complete: Callback for completion of the source.
Recommended for debugging purpose.

How to overwrite global event handler in nested Vue component, and later use the previous one?

I am working in Vue and also i use VueRouter, VueX and VueWebsocket. My App has component called App which holds all other components inside itself. Also I have websocket event which is set globally like this:
this.$options.sockets.onmessage = (websocket) => { /* sth1 */ }
When it gets any data from websocket, sth1 is called. it works like charm. However deep inside App component is another component, let's call it InputComponent. It may be included in App or not becaue it is single page aplication and some parts do include InputComponent, and some do not. Inside InputComponent there is also:
this.$options.sockets.onmessage = (websocket) => { /* sth2 */ }
And of course it overwrites function on message so sth1 will never be executed if InputComponent is nested by App component. It is quite obvious. However if i remove (in next SPA page), and InputComponent disappears i still have my onmessage event overwritten which i would like to have in original version.
I could ofcourse make some kind of merging functionalities of sth1 and sth2 in App component or InputComponent but it is repeating myself.
Here comes the question - is there a way to return original version of onmessage event without reloading whole App Component? In other words: can i have temporary overwritten function and then come back to its functionalities? Something like extending an eent with new functionalities of sth2.
I hope you get the idea!
K.
The general way to do that would be to use addEventListener and removeEventListener. So in the input component
created() {
this.$options.sockets.addEventListener('message', handleMessage);
},
destroyed() {
this.$options.sockets.removeEventListener('message', handleMessage);
}
Note that this approach doesn't prevent the original handler from also receiving the events. Without knowing more about the app architecture, it's hard to suggest the best way to avoid this behavior, but perhaps you can set a messageHandled flag on the event in the component's handler; then check that flag in the parent.

How to correctly subscribe to Changed sequence of ReactiveObject?

Another question about ReactiveUi. I have a ViewModel for an edit form. Model is ReactiveObject. I want to enable savecommand only when changes of object was take place. My try:
var canSaveCommand =
this.WhenAnyValue(vm => vm.CurrentClient)
.Where(client => client != null)
.Select(client =>
client.Changed
)
.Any();
But when the form appears the SaveCommand is already enabled. Where my mistake?
You want to use Switch not SelectMany. SelectMany will not unsubscribe from the previous client. It will merge events from all clients. Switch unsubscribes from the previous client before it subscribes to the next.
var canSaveCommand =
this.WhenAnyValue(vm => vm.CurrentClient)
.Where(client => client != null)
.Select(client =>
client.Changed
)
.Switch()
.Any();
For example the following code makes it clear. Let's say we have a class called AudioChannel It generates audio frames we can can process and send to the speaker.
public class IAudioChannel {
public IObservable<AudioFrame> AudioFrameObservable {get;}
}
Then we might have a list of audio nodes that the user can select but we only want the most current sending audio to the speaker. The below class makes available the currently selected audio node as an observable.
public class AudioListViewModel {
public class IObservable<IAudioChannel> CurrentAudioChannelObservable {get;}
}
Now consider the following code
AudioListViewModel viewModel;
viewModel
.CurrentAudioChannelObservable
.SelectMany(current=>current.AudioFrameObservable)
.Subscribe(frame=>frame.Play());
vs
AudioListViewModel viewModel;
viewModel
.CurrentAudioChannelObservable
.Select(current=>current.AudioFrameObservable)
.Switch()
.Subscribe(frame=>frame.Play());
In the first version as we change the selection of audio nodes we add more and more subscriptions. The audio output quickly becomes a garbled mess of mixed channels. In the second version only one channel is subscribed to at a time and the audio output only plays the output from a single channel.
Many people make this mistake when starting out with RX. For example I found a bug in the ReactiveUI framework that used SelectMany instead of Switch.
However
There is a built in way within ReactiveUI to achieve this in a clear way
There is actually another way to achieve what you want and I will put it in another answer just to show you how to use ReactiveUI.
var canSaveCommand =
this
.WhenAnyObservable(vm => vm.CurrentClient.Changed)
.StartWith(false);
Note that null doesn't have to be explicity handled though you should start with false to make sure a value exists when no observable is available to start with.
WhenAnyObservable
WhenAnyObservable acts a lot like the Rx operator CombineLatest, in
that it watches one or multiple observables and allows you to define a
projection based on the latest value from each. WhenAnyObservable
differs from CombineLatest in that its parameters are expressions,
rather than direct references to the target observables. The impact of
this difference is that the watch set up by WhenAnyObservable is not
tied to the specific observable instances present at the time of
subscription. That is, the observable pointed to by the expression can
be replaced later, and the results of the new observable will still be
captured. An example of where this can come in handy is when a view
wants to observe an observable on a viewmodel, but the viewmodel can
be replaced during the view's lifetime. Rather than needing to
resubscribe to the target observable after every change of viewmodel,
you can use WhenAnyObservable to specify the 'path' to watch. This
allows you to use a single subscription in the view, regardless of the
life of the target viewmodel.
Try changing your Select to a SelectMany. That will then give you an Observable of the changes to be passed into Any instead of an Observable of an Observable of the changes to be passed into Any.

RxJS. Creating an Observable from 2 properties

I'm trying to wrap my head around reactive programming and observables.
What is the reactive way to solve the following scenario?
I have an object with 2 properties.
At anytime, one, both or neither of these properties can be set.
Each of these properties dispach events that I can listen to.
Only when both properties are set I want to listen to their update events and run some kind of aggregation on their properties.
One possible solution is to create a stream from each property and then combine the streams using combineLatest.
combineLatest will not produce a value until both inputs have produced a value. After both inputs have produced a value, the stream will update every time either value changes. See code below:
const property1$ = Rx.Observable.fromEvent(button1, 'click');
const property2$ = Rx.Observable.fromEvent(button2, 'click');
const aggregateWhenBothAreClicked$ = property1$
.combineLatest(property2$)
.map([property1,property2])=>doStuff(property1,property2))
The doStuff function will not be called until both buttons have been clicked. Once both buttons have been clicked, the doStuff function will be called everytime afterwards.

Resources