Skip to content

Feat: Add tapOnce and tapOnceOnFirstTruthy Operators#490

Open
endlacer wants to merge 2 commits intongxtension:mainfrom
endlacer:feature/tap-once
Open

Feat: Add tapOnce and tapOnceOnFirstTruthy Operators#490
endlacer wants to merge 2 commits intongxtension:mainfrom
endlacer:feature/tap-once

Conversation

@endlacer
Copy link
Contributor

This pull request adds two new standalone RxJS operators, tapOnce and tapOnceOnFirstTruthy, to the utility library. These operators allow for conditional execution of functions based on emitted values.

tapOnce: Executes the provided function only once when the value at the specified index is emitted.
tapOnceOnFirstTruthy: Executes the provided function only once when the first truthy value is emitted.

What are your thoughts on these operators? They seem particularly useful for scenarios where you need to initialize something, such as a modal element, as soon as the first value from a source is emitted.

This is my first PR on GitHub, so I appreciate your patience :)! Any contributions, feedback, or change requests are more than welcome.

@endlacer endlacer marked this pull request as ready for review September 2, 2024 08:08
@eneajaho
Copy link
Collaborator

eneajaho commented Oct 1, 2024

Hello @endlacer
Thanks for creating this PR,
I would like to know more about the usecases for this operator, can you give some examples which this solves.
Currently it's hard to understand where this would be useful and if other projects can benefit from this.

@endlacer
Copy link
Contributor Author

endlacer commented Oct 1, 2024

hi @eneajaho ,
I used the tapOnceOnFirstTruthy operator for initialization of a modal dialog. For example, I have an open$ Subject of type ModalData. The ModalComponent subscribes to an Observable derived from this Subject. When it receives its first truthy value, it performs some initialization before opening the modal in the subscribe block.

Here's a simplified example:

import { Subject } from 'rxjs';
import { tapOnceOnFirstTruthy } from './operators';

class ModalComponent {
  private open$ = new Subject<ModalData | null>();

  constructor() {
    this.open$
      .pipe(
        tapOnceOnFirstTruthy((data) => {
          // Perform one-time initialization
          this.initializeModal(data);
        })
      )
      .subscribe((data) => {
        if (data) {
          this.openModal(data);
        } else {
          this.closeModal();
        }
      });
  }

  private initializeModal(data: ModalData) {
    // One-time setup logic
  }

  private openModal(data: ModalData) {
    // Logic to open the modal
  }

  private closeModal() {
    // Logic to close the modal
  }
}

This approach ensures that the initialization logic runs only once, even if the modal is opened and closed multiple times.

Another example could be a user filling out a multipage form and when reaching the midpoint you want to log that to some analyze-backend. But you only want to do it once and not on every back/forth navigation. This can be done with a sperate subscription with filter + take(1), but this operator is cleaner.


Concerning the API: It would be cleaner and more consistent to also allow the user to provide a tapIndex to the tapOnceOnFirstTruthy (and then rename if oc) method, similar to how it's implemented in the tapOnce method. This would give users more control over when the truthy check is performed.

@endlacer
Copy link
Contributor Author

Any update on this? :)

@nx-cloud
Copy link

nx-cloud bot commented Nov 18, 2025

View your CI Pipeline Execution ↗ for commit f12e1f1

Command Status Duration Result
nx affected --target=build --parallel=3 --exclu... ✅ Succeeded <1s View ↗
nx affected --target=test --parallel=3 --exclud... ✅ Succeeded 5s View ↗
nx affected --target=lint --parallel=3 ✅ Succeeded 38s View ↗
nx-cloud record -- nx format:check ✅ Succeeded 1s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-10 06:44:30 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants