I have a form where the user can enter markdown-formatted text in a textarea. I'd like to show a quasi live preview of the parsed markdown next to the field.
Exactly like the StackOverflow question form. ;-)
The values of the textarea are being emitted through an RxJS Observable but I don't want to refresh the preview for every new value. Instead I'd like to refresh the preview only after the user has stopped typing for say 500ms.
Here's a tentative diagram (first line is the raw values emitted by the textarea as the user types, second line is what I'd like to obtain; a value is emitted only once a specific delay WITH NO EMISSION has elapsed):
t---t--ttt------tt-ttt------t---|
----------------t-----------t---|
What would be the syntax to achieve this?
You can just use the debounceTime() operator.
You can also chain it with distinctUntilChanged(), to avoid recomputing the HTML if the user, for example, adds two characters and deletes them
I would recommend auditTime for your use case in terms of UX.
If the user is typing continuously , then using debounceTime , the Quasi Preview wouldn't generate until there is a pause.
However, in auditTime, the Quasi Preview is generated for every time interval as long as there is a type event.
I believe auditTime gives a better UX.
Both auditTime and debounceTime will initially start a timer when an
event comes in. Both will wait the given amount of time before they
emit an event. The difference is that debounceTime resets the timer
whenever a new event comes in while auditTime does not. auditTime will
emit the most recent event after the given number of milliseconds
whether or not it is still receiving events. debounceTime will wait
for a gap in the events. You said you read the documentation but just
to double check I have found this document particularly helpful.
Some references which I found useful.
https://medium.com/#jvdheijden/rxjs-throttletime-debouncetime-and-audittime-explained-in-examples-c393178458f3
Difference between audit and debounce in rxjs?
Related
I'm trying to understand throttleTime vs debounceTime and which one is to be used when?
I have an upvote button that makes an API request to the backend (which counts the votes). User can submit button multiple times, but I'd like to limit the times per second button can be pressed.
I know throttleTime and debounceTime operators can do that, but which one should I choose?
const upvoteClicks = fromEvent(this.el.nativeElement, 'click')
.pipe(debounceTime(500))
.subscribe(() => this.myService.postUpvote(this.postId));
I think in your case throttleTime works a little bit better, because you want to make the api request as soon as user clicks the button.
Both throttleTime and debounceTime ignore the events which come in the meantime, but throttleTime emits right away, while
debounceTime waits for additional delay.
You can visually see that very well at https://rxmarbles.com
What is more, throttleTime vs debounceTime in RxJS article provides a good overview of both operators.
(A more simple answer)
Say a user clicks a button that triggers a request (example):
Throttle time = can limit the number of clicks so only 1 goes through every second (prevents button spamming)
Debounce time = can add a delay before each request goes through (you press the button then nothing happens for 1 seconds, then your request goes through)
1 second was just an example. You can enter whatever you'd in the debounceTime() or throttleTime() - in ms
The accepted answer has clearly pointed out the difference between throttleTime and debounceTime.
However I'd like to bring up a slightly different option in your particular situation, that is exhaustMap. exhaustMap is an operator that ignores every new projected Observable if the previous one has not yet completed. So the first API request to backend has to be completed before the user can execute it the second time. It's useful if the API data is bouncing back very slowly, slower than the fixed time you set, it won't trigger any further API call until the previous one completed.
You can read more about exhaustMap here.
const upvoteClicks = fromEvent(this.el.nativeElement, 'click')
.pipe(
exhaustMap(() => this.myService.postUpvote(this.postId))
)
.subscribe(() => console.log('upvoted!'))
I often use combineLatest to combine 3 or 4 Observables to calculate a simple condition.
If one of the 'combined' Observables doesn't emit then this will block until it does. It can be very tricky to debug if later down the line something that has always emitted immediately stops emitting.
Side-note: I'm specifically needing this for UI related logic, where there may be observables that represent things like screen width / scroll position / etc. So they're supposed to always be there - but if it breaks suddenly (especially on mobile) it's difficult to track down what's blocking it.
So what I need is something like combineLatestImmediate that errors if all inputs aren't immediately available. When I say 'available right away' it's typically something that comes from a centralized data store, or a behaviorsubject (which of course will always have a value). But when it breaks...ugh.
Is there a better way than:
combineLatest(obs1, obs2, obs3)
.pipe(timeoutWith(0, throwError('Expected obs all to be available')))
or even:
// note: take(1) is required or the wrong observable
// may get reported if the source hasn’t closed
combineLatest(obs1.pipe(take(1), timeoutWith(0, throwError('obs1 has no value'))),
obs2.pipe(take(1), timeoutWith(0, throwError('obs2 has no value'))),
obs3.pipe(take(1), timeoutWith(0, throwError('obs3 has no value'))));
You could put a non zero value for timeout if you wanted a grace period, or make this into a custom operator. But I'm finding a need more and more for this.
It's a safety / sanity thing, to save time debugging.
Also I'm not looking for forkJoin (which short-circuits if any of the inputs are EMPTY). I'm talking about when a value is just not immediately available - usually .
I have a use case of a "quick search' box where the user types first few letters of the search criteria, and the system shows the list of results in real time. E.g. if you type "J" in a box for the country name, it would show "Jamaica, Japan, Jordan". When you proceed to type "Ja", it would show just Jamaica and Japan, and leave Jordan out.
Each search request is an AJAX call. The trouble with AJAX calls is that the responses may not come in the same order as requests. E.g., the following sequence of events is possible:
Request search results for "J".
Request search results for "Ja".
Receive response to request #2: [Jamaica, Japan]
Receive response to request #1: [Jamaica, Japan, Jordan]
If the system blindly shows the last response, it will end up in an inconsistent state, when the search box contains "Ja", but "Jordan" is on the suggestion list. The system should be smart and discard response #4, since it is no longer relevant.
Does RxJS provide a clean way to discard responses to anything but the last issued request?
Keep in mind that "last request" changes over time as new requests are produced. I searched the documentation and did not find much. Most tutorials simply ignore this problem.
&tldr;
You want switchMap instead of flatMap or mergeMap
Breakdown
I just did a quick google search for "rxjs smart search" and found two of the first two hits dealt with the problem, here and here.
But for future readers the answer is to use switchMap or flatMapLatest as it used to be called. As the name would imply, it both switches and maps. What does that mean, well from the docs here it,
Projects each source value to an Observable which is merged in the output Observable, emitting values only from the most recently projected Observable.
In plain terms, like flatMap each single event passed into the callback function of switchMap should result in a stream (or stream-like thing). The result of a new emission is that only results from the latest stream are listened to while there is a "best-effort" cancellation made on the original. This happens for each new emission. By best effort it means that if there is a way to halt progress on the stale stream it will be halted, but for some data structures (read: Promises) there is no way to actually cancel it once it is in progress so the best the library can do is simply ignore the result.
Using event structures in LabView can get confusing, especially when mixing them with a mostly synchronous workflow. My question is, when an event structure exists in one frame of a sequence, how can I force it to ignore events (e.g. mousedown on a particular button) that were triggered while the workflow is in another frame of the sequence?
Currently, the event structures only process the events at the correct frame in the sequence, but if one was triggered while the workflow is in the previous frame, it processes those too and I want it to ignore any events that weren't triggered in the frame that the event structure exists within.
http://puu.sh/hwnoO/acdd4c011d.png
Here's part of my workflow. If the mousedown is triggered while the left part is executing, I want the event structure to ignore those events once the sequence reaches it.
Instead of placing the event structure inside your main program sequence, put it in a separate loop and have it pass the details of each event to the main sequence by means of a queue. Then you can discard the details of the events you don't want by flushing the queue at the appropriate point.
Alternatively you could use a boolean control to determine whether the event loop sends event details to the queue or discards them, and toggle the boolean with a local variable from the main sequence.
You can register for events dynamically. Registration is the point in time at which the event structure starts enqueueing events, and in your case this happens when the VI the event structure is in enters run mode (meaning it's executing or one of its callers is). You can change it so that you register using the Register for Events node and then you would only get events from that point on. When you unregister you will stop getting events.
There's a very good presentation by Jack Dunaway going into some details about events here.
You can find the code for it here.
In LabVIEW 2013 and later there are additional options for controlling the events queue, but I won't go into them here.
http://puu.sh/hwsBE/fe50dee671.png
I couldn't figure out how to flush the event queue for built-in event types like mousedown, but I managed to get around that by creating a static reference to the VI and setting the cursor to busy during the previous sequence, disabling clicking. Then when the sequence for the event structure is reached, I unset the cursor from busy, which re-enables clicking.
I have a searchbox which listens to keypress and calls the controller action to get results
These results shown for autocomplete as a dropdown. It works functionally.
Currently I have it set on each key press.
The problem is if I type 4/5 characters and debug the app, same line gets executed 4/5 times.
Is there a way to prevent this on the controller (I guess no)?
Is is good to send the request to the server on every character or do it based on time delay such as send the request after every 1 second delay while user keeps typing?
Thanks for reading.
add this to auto complete so it wait until minimum characters reach
minLength: (integer value what you preferred )
cheers