npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@angular-kit/rx-stateful

v1.8.0

Published

Powerful RxJs extensions to level up your streams with stateful operators.

Downloads

81

Readme

@angular-kit/rx-stateful

rxStateful$ is a powerful RxJs operator that wraps any sync or async Observable and provides a stateful stream. It does offer out of the box

  • 🔄 loading state
  • ❌ automatic error handling
  • 🔄 refresh-mechanisms
  • 🔴 multicasted stream
  • ⚙️ powerful configuration possibilities e.g. to keep the last value on refresh
  • ⚡️ non-flickering loading state for great UX

Hint: You can use it on both sync and async Observables. However the real benefits you will get for async Observables.

Installation


npm install @angular-kit/rx-stateful
yarn add @angular-kit/rx-stateful
pnpm add @angular-kit/rx-stateful
  

Demo

A live demo is available on here

Usage

rxStateful$ as standalone function

Sync source Observable

import { rxStateful$ } from '@angular-kit/rx-stateful';

/**
 * Sync Observable will return: 
 * [
 * { value: 1, hasValue: true, context: 'next', hasError: false, error: undefined },
 * { value: 2, hasValue: true, context: 'next', hasError: false, error: undefined },
 * { value: 3, hasValue: true, context: 'next', hasError: false, error: undefined },
 * ]
 */
const stateful$ = rxStateful$(of(1, 2, 3));

Async source Observable

Basic Usage

import { rxStateful$ } from '@angular-kit/rx-stateful';

/**
 * Async Observable will return: 
 * [
 * { value: null, hasValue: false, context: 'suspense', hasError: false, error: undefined },
 * { value: SOME_VALUE, hasValue: true, context: 'next', hasError: false, error: undefined },
 * ]
 */

const stateful$ = rxStateful$(from(fetch('...')));


const trigger$$ = new Subject<number>()
const refresh$$ = new Subject<void>()
const stateful$ = rxStateful$((id: number) => from(fetch(`.../${id}`)), {
    sourceTriggerConfig: {
        trigger: trigger$$
    },
    refetchStrategy: withRefetchOnTrigger(refresh$$)
});

API

rxStateful$ returns a Observable of with following properties:

  • value - the value
  • hasValue - boolean if a value is present
  • context - the context of the stream ('suspense', 'next', 'error', 'complete')
  • hasError - boolean if an error is present
  • error - the error, if present
  • isSuspense - suspense/loading state

Configuration

rxStateful$ provides configuration possibility on instance level:

Configuration on instance level

You can also provide a configuration on instance level. This will also override the global configuration (if present).

rxStateful$ takes a configuration object as second parameter. The following options are available:

  • keepValueOnRefresh - boolean if the value should be kept when the refreshTrigger$ emits. Default: false
  • keepErrorOnRefresh - boolean if thel last error should be kept when the refreshTrigger$ emits. Default: false
  • refreshTrigger$ - a Subject or Observable that triggers the source again. Default: not set. deprecated use refetchStrategies
  • refetchStrategies - single or multiple RefetchStrategies to trigger the source again. Default: not set
  • suspenseThresholdMs - number of milliseconds to wait before emitting the suspense state. Default: 0
  • suspenseTimeMs - number of milliseconds to wait before the next state after the suspense state. Default: 0

[!TIP] A few more words about the suspenseThresholdMs and suspenseTimeMs configuration. This is a quite powerful feature which will result in a better UX when preventing flickering loading states. What does flickering loading states mean? When you show a loading indicator/spinner based on the isSuspense-property then a common scenario is that you show a spinner for a very short tim for fast requests resulting in some flickering. To prevent this it is better to wait a certain amount of time before showing a spinner (suspenseThreshold). If then the request takes longer thant the threshold-time a spinner will be shown for at least another amount of time (suspenseTime). That way you can prevent flickering spinners.

rxStateful$ provides exactly this feature and will only emit the suspense-state if a async-operation takes longer than the specified suspenseThresholdMs for at least suspenseTimeMs. A reasonable configuration of these two values would be to set them both to 500ms.

[!IMPORTANT] The default value for suspenseThresholdMs and suspenseTimeMs is 0, therefor by default you will not use the non-flickering loading state feature. It is choosen that way to break existing behavior. This might change in a future major version.

Configuration Example
import { rxStateful$ } from '@angular-kit/rx-stateful';

const rxStateful$ = rxStateful$(someSource$, { keepValueOnRefresh: true });
refetchStrategies
  • withRefetchOnTrigger
  • withAutoRefetch

Usage via RxStatefulClient

In order to use RxStatefulClient you first need to provide it, e.g. in your AppModule:

import {provideRxStatefulClient} from "@angular-kit/rx-stateful";

@NgModule({
    providers: [
        provideRxStatefulClient()
    ],
})
export class AppModule {}

RxStatefulClient offers a request-method which basically has the same signature as rxStateful$ - so there'is no difference in usage.

Global configuration

provideRxStatefulClient() can be configured:

import {provideRxStatefulClient, withConfig} from "@angular-kit/rx-stateful";

@NgModule({
    providers: [
        provideRxStatefulClient(withConfig({ keepValueOnRefresh: true}))
    ],
})
export class AppModule {}

The global configuration will be used for every request-call. You can still override the global configuration by providing a configuration object as second parameter to request-method.

Configuring refresh behaviour

Both rxStateful$ and RxStatefulClient can be configured to refresh the source (e.g. make a HTTP call again).

To define the refresh behaviour you can make use of so called RefetchStrategy's. Right now there are following strategies built in: withAutoRefetch and withRefetchOnTrigger.

Usage on rxStateful$

```typescript
    const instance = rxStateful$(fetch(), { refetchStrategy: [withAutoRefetch(1000, Infinity)] })

Usage on RxStatefulClient



const client = inject(RxStatefulClient);
const instance = client.request(fetch(), { refetchStrategy: [withAutoRefetch(1000, Infinity)] })

All strategies can be cominded in an arbitrary way.

In the future there will come more strategies built in, as well as an easy way to define custom strategies. However defining custom strategies is already possible by implementing the RefetchStrategy interface.

Testing

Please have a look at the testing documentation.

Versioning

This project follows Semantic Versioning.

  • Version 1.x.x supports Angular >=14.0.0

License

MIT

Contributing

Any Contributions are welcome. Please open up an issue or create PR if you would like to contribute.

See CONTRIBUTING.md for more information.