BehaviourSubject hit multiple times if there is only one value - javascript

I have used behaviourSubject in shared service to get the current value while clicking a button.It is working as expected but some times the api call inside the subscribe block of behavioursubject hits multiple times.
what will be the issue??

There can be any of the following reasons:
This happens, when you subscribe to BehaviorSubject in a block of code that executes multiple times. Example if you subscribe in ngAfterViewChecked life cycle hook of angular component that executes multiple times.
You never unsubscribed but every time app loads the component, subscribe your behaviour subject.
Subscriber of BehaviorSubject always executes at least once, because BehaviorSubject requires a default argument when created and emits the passed default argument at least once, if you call .next() method only once on the instance of BehaviorSubject, Subscriber will execute twice. 1st time for default value passed while creating instance of BehaviorSubject, 2nd time for the value you passed by calling .next method on the instance of BehaviorSubject.
Did I answer your question ?
If not, please provide the code snippet, so that we could understand the problem better.

Related

Check if the Parameter has been created inside USD Data Parameters

I am trying to built a logic where I am running an action call with uii action CreateEntity. The action call creates a record in CRM Custom Entity. Now, the action call is being fired multiple times and that is because it is attached in the BrowserDocumentComplete Event which is being fired multiple times.
Now since that action call is being fired multiple times therefore multiple records are being created inside CRM. I want to make it stop after it creates the first record and what happens is if it creates a first record a parameter is created inside USD DataParameters.
So, I want to check through Scriptlet preferably that if the parameter lets name it RecordCreated has been created inside USD then make the action call stop.
Something like this if (RecordCreated Exists) then stop else run
Ideally BrowserDocumentComplete event won't get triggered multiple times in USD. Is it the PageLoadComplete event normally gets triggered twice. That is something which you need to check once before thinking of another solution.
Coming to your issue, if the browser document complete is not working as expected in your case, another option is to do a check whether the record is created before running the action call the second time. For that what you can do is, whenever an action call is executed you will get an object $Result in the USD data parameters. Look for the object and get the guid of the CRM record being created. You should be able to access that something like this,
$Result.<<Name of your action call goes here>>
In your same action call, check whether the output of the above code and see whether that is empty of a GUID. If its not empty that means your action call was executed previously, otherwise execute the action call to create the record.
Hope that helps.
I believe that BrowserDocumentComplete fires each time either a page or an iframe finishes loading. Instead, use an event that generally only fires once, like DataReady or PageReady. This assumes that DataReady and PageReady are available in your version of USD.
DataReady and PageReady can still fire multiple times during reload / refresh scenarios, so you can still have the same problem. To mitigate this, check for the existence of the data parameter that is created when the record is created. In the condition check, allow the replacement parameter to be replaced by an empty string when it doesn't exist, using the '+' modifier. If your Action Call is named "Create Custom Entity Record", then your condition expression will probably look something like this:
[[$Result.Create Custom Entity Record]+]===""
Now, even if the Action Call is attempted multiple times, it should only fire once and be prevented from firing subsequently. Subsequent attempts should be shaded yellow in Debugger, indicating "ConditionFailed".

Subscription in Tracker.autorun causes publish callback to fire multiple times

I'm working in a ReactJS and Meteor project and I found a strange behavior I'm gonna describe here:
There is a Tracker.autorun block with a Meteor.subscribe call inside. So far, so good. In the server side, there is a matching Meteor.publish which declares a callback.
As far as I understand, the Meteor.publish callback should fire once for each subscription received, but somehow this callback is firing 3~4 times for a single subscription.
In my last test the Tracker.autorun block executed 4 times, the subscribe only executed 1 single time and the callback fired 4 times.
The Meteor.subscribe only runs once, even the tracker runs several times. How could it cause the callback to fire more the once?
Does it make sense?
Do you know what could explain such behavior?
If you need any other information, just let me know.
Thanks in advance
Meteor.publish('current-user', function currentUser(credentials) {
return Users.find();
});
Tracker.autorun((c) => {
if (!currentUserHandler) {
currentUserHandler = Meteor.subscribe('current-user', this.credentials);
}
});
You should expect that the autorun will fire twice as a normal condition, once without data, and the second with some data.
That is to allow you to show a "loading" state before the data arrives.
You are subscribing to the users collection, which is a special collection. Meteor uses it for authentication, and also to record session activity. You are doing a Users.find(), which is an unfiltered query on the whole users collection, so any modification to any user will cause it to fire. You also won't be able to see all of the users records (for security reasons).
It's probable that you are storing additional data on the users record, hence the need for you to subscribe to it. I would recommend that you consider storing this data in another collection, such as 'members', 'visitors', 'profiles' or whatever name suits you. Things are likely to work better that way.

Render time-based Observables in Angular without overwhelming change detection

We have a number of components in our Angular application that need to regularly display new values every second that are unique to each component (countdowns, timestamps, elapsed time, etc). The most natural way to is to create observables that use the RxJS timer and interval factory functions. However, these trigger Angular change detection at every interval for the entire app as many times as the interval function was called. If we have dozens of components on the page, this triggers change detection for the entire app dozens of times every second or time period, creating a large performance overhead.
So far there are two ways I've attempted to solve the problem. A good answer to either would be very helpful - ideally both. I want to avoid manual trigger of change detection and instead rely on new values emitted from Observables and have the async pipe/OnPush change detection strategy be responsible for triggering change detection. If this isn't possible, I'd like to understand why.
Is there any way to disable or prevent RxJS timer or interval functions from triggering Angular change detection? Using NgZone zone.runOutsideAngular(() => this.interval$ = interval(1000) ... ) does not appear to do this. StackBlitz example: https://stackblitz.com/edit/angular-zo5h39
Alternatively, if I create an Observable stream using an RxJS Subject combined with setInterval called inside zone.runOutsideAngular, why isn't change detection triggered for the child component when a new value is emitted from the subject? StackBlitz example: https://stackblitz.com/edit/angular-yxdjgd
Is there any way to disable or prevent RxJS timer or interval functions from triggering Angular change detection? Using NgZone
zone.runOutsideAngular(() => this.interval$ = interval(1000) ... )
does not appear to do this.
It's because observables are cold and the value producer (setInterval) is only executed when a subscription happens. Read more here. Although this code is executed outside of Angular zone:
() => this.interval$ = interval(1000) ...
it doesn't actually immediately invoke the value producer inside interval operator. It will be later invoked when AsyncPipe in the IntervalInnerComponent subscribes. And this happens in inside Angular zone:
Using subject in the next alternative you make it hot and subscribe immediately outside of Angular zone.
Alternatively, if I create an Observable stream using an RxJS Subject combined with setInterval called inside zone.runOutsideAngular... setInterval values are being created (they can be subscribed to
manually), but the async pipe does not appear to be triggering change
detection
Because Async Pipe doesn't trigger change detection. It simply marks a component and all its ancestors for check during the following change detection whenever it will be. See this answer or this article for more details. Zone.js triggers change detection. But since you're running setInterval outside Angular zone, it doesn't trigger it. Under this setup you have a few options:
inject ChangeDetectorRef and manually trigger change detection for the component and its ancestors
inject ApplicationRef and manually trigger change detection for the entire application

Unexpected Firebase Firestore collection subscription behaviour

I am experiencing some interesting behaviour regarding a subscription on a collection's valueChanges.
Immediately after creating a doc, the collection's subscription is invoked, but instead of an array of many documents I am only receiving an array of size one - the single, newly created document.
After having a read through this (Firestore Docs | Get Realtime Updates) I am still slightly confused.
Local writes in your app will invoke snapshot listeners immediately. This is because of an important feature called "latency compensation." When you perform a write, your listeners will be notified with the new data before the data is sent to the backend.
Does this explain the behaviour I am seeing?
Here is a stackblitz demonstrating the problem. Just uncomment out the commented line in ngOnInit() and reload to see what I believe is expected behaviour.
I can solve this by either having an empty subscription listening to this collection elsewhere, or duplicating the take(1) subscription code directly before
Thats a good catch. Pretty sure you are right - valueChanges() as docs states:
The current state of your collection. Returns an Observable of data as
a synchronized array of JSON objects.
And as you found yourself:
Local writes in your app will invoke snapshot listeners immediately.
So this is what happens:
Your addPizza() is an async function. It sends request to backed to add new pizza. But it doesnt wait for anything and jumps to your second function - this.getPizzasAsyncAwait(). And because that local write invokes listener immediately, your Observable emits that value and broadcasts it. And since you also use Rxjs's take(1) - after that it unsubscribes. That also explains why take(2) brings all other records. You can move your getPizzasNormal() method to OnInit() and you'll receive the whole collection.
The firebase js sdk handles optimistically the add, before getting the collection values, the collection is not defined yet. Once you add a value the collection contains 1 value and then is updated by the server side values.
If you want to avoid getting this intermediate state when the collection values are set only from local changes, you can subscribe before start changes to be done before subscribing :
this.piazzaRef.add({
name: name,
addedAt: new Date().toISOString()
}).then(() => {
this.getPizzasAsyncAwait();
this.getPizzasNormal();
});
I updated your example here

#ngrx/effects BehaviourSubject giving last value to subscribers

Something I noticed the other day. I was subscribing to the Actions stream inside #ngrx/effects. I noticed (an issue for me) where a component, which subscribes to Actions late, receives the last dispatched action. This I can see is because the dispatcher inside #ngrx/store is a BehaviourSubject and quoting the RxJS docs:
Rx.BehaviorSubject class
Represents a value that changes over time. Observers can subscribe to the subject to receive the last (or initial) value and all subsequent notifications.
Unfortunately, I'd like to subscribe to the actions stream without retrieving the last value. It creates problems for me like showing error messages when a user returns to a page.
The difference between BehaviorSubject and Subject (which does it the way I'd like) is demo'd here:
https://codepen.io/anon/pen/zwgype
Is there any way of achieving this?
You can skip the first value with the 'skip' operator:
someBehaviorSubject.skip(1)

Categories