An open API service indexing awesome lists of open source software.

https://github.com/kosich/rxjs-proxify

Turns a Stream of Objects into an Object of Streams
https://github.com/kosich/rxjs-proxify

observable proxy reactive-programming rxjs rxjs-observables

Last synced: over 1 year ago
JSON representation

Turns a Stream of Objects into an Object of Streams

Awesome Lists containing this project

README

          





{ πŸ‘“ }


Turn a Stream of Objects into an Object of Streams




NPM
Bundlephobia
MIT license







Access values inside RxJS Observables as if they were directly available on the stream!

```ts
stream.pipe(pluck('msg')).subscribe(…);
// turn ↑ into ↓
stream.msg.subscribe(…);
```

With good TypeScript support! 😲 Roughly speaking:

```ts
proxify( Observable<{ msg: string }> ) β‰ˆ Observable<{ msg: string }> & { msg: Observable }
```

**But recursively.** So `stream.msg` is a Proxy itself, allowing you to `stream.msg.length.subscribe(…)`!

Proxify lets you **access Observable API** as well as **pluck props** and **call methods** at any depth of an Observable, Subject, or BehaviorSubject! See the [API](#-api) and [Examples](#-examples) sections to learn more.

## πŸ“¦ Install

```
npm i rxjs-proxify
```

or [try it online](https://stackblitz.com/edit/rxjs-proxify-repl?file=index.ts)!

## πŸ›  API

There are two methods available to you: [`proxify`](#proxify) and [`statify`](#statify)

## Proxify

`proxify(stream)` will wrap your Observable, Subject or BehaviorSubject in a Proxy:

**Observable Proxy**
subscribe at any depth

```ts
const observable = proxify( of({ p: 'πŸ‘' }) );
observable.subscribe(console.log); // > { p: πŸ‘ }
observable.p.subscribe(console.log); // > πŸ‘
```

**Subject Proxy**
subscribe at any depth, push at the root

```ts
const subject = proxify(new Subject<{ p: string }>());
subject.subscribe(console.log);
subject.p.subscribe(console.log);
subject.next({ p: 'πŸ₯' }); // > { p: πŸ₯ } // > πŸ₯
```

**BehaviorSubject Proxy**
subscribe at any depth, push at any depth, synchronously read the current state

```ts
const behavior = proxify(new BehaviorSubject({ p: 'πŸ–' }));
behavior.p.subscribe(console.log); // > πŸ–
behavior.p.next('πŸ‡'); // > πŸ‡
console.log(behavior.p.value) // > πŸ‡
```

### Statify

`statify(value)` will put the value in a BehaviorSubject Proxy and add a `distinctUntilChanged` operator on each property access.

**State Proxy**
subscribe to distinct updates at any depth, push at any depth, synchronously read the current state

```ts
// create a state
const state = statify({ a: '🐰', z: '🏑' });

// listen to & log root state changes
state.subscribe(console.log); //> { a:🐰 z:🏑 }

// update particular substate
state.a.next('πŸ‡'); //> { a:πŸ‡ z:🏑 }

// read current values
console.log(state.z.value + state.a.value); //> πŸ‘πŸ‡

// update root state, still logging
state.next({ a: 'πŸ‡', z: '☁️' }) //> { a:πŸ‡ z:☁️ }

// and then…
state.z.next('πŸŒ™'); //> { a:πŸ‡ z:πŸŒ™ }
state.a.next('πŸ‡πŸ‘€'); //> { a:πŸ‡πŸ‘€ z:πŸŒ™ }
state.z.next('πŸ›Έ') //> { a:πŸ‡πŸ‘€ z:πŸ›Έ }
state.a.next('πŸ’¨'); //> { a:πŸ’¨ z:πŸ›Έ }
```

See Examples section for more details.

## πŸ“– Examples

### Basic

```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";

const o = of({ msg: 'Hello' }, { msg: 'World' });
const p = proxify(o);
p.msg.subscribe(console.log);

// equivalent to
// o.pipe(pluck('msg')).subscribe(console.log);
```

### With JS destructuring

Convenient stream props splitting

```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";

const o = of({ msg: 'Hello', status: 'ok' }, { msg: 'World', status: 'ok' });
const { msg, status } = proxify(o);
msg.subscribe(console.log);
status.subscribe(console.log);

// equivalent to
// const msg = o.pipe(pluck('msg'));
// const status = o.pipe(pluck('status'));
// msg.subscribe(console.log);
// status.subscribe(console.log);
```

**⚠️ WARNING:** as shown in "equivalent" comment, this operation creates several Observables from the source Observable. Which means that if your source is _cold_ β€” then you might get undesired subscriptions. This is a well-known nuance of working with Observables. To avoid this, you can use a multicasting operator on source before applying `proxify`, e.g. with [`shareReplay`](https://rxjs.dev/api/operators/shareReplay):

```ts
const { msg, status } = proxify(o.pipe(shareReplay(1)));
```

### With pipe

Concatenate all messages using `pipe` with `scan` operator:

```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";
import { scan } from "rxjs/operators";

const o = of({ msg: 'Hello' }, { msg: 'World' });
const p = proxify(o);
p.msg.pipe(scan((a,c)=> a + c)).subscribe(console.log);

// equivalent to
// o.pipe(pluck('msg'), scan((a,c)=> a + c)).subscribe(console.log);
```

### Calling methods

Pick a method and call it:

```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";

const o = of({ msg: () => 'Hello' }, { msg: () => 'World' });
const p = proxify(o);
p.msg().subscribe(console.log);

// equivalent to
// o.pipe(map(x => x?.map())).subscribe(console.log);
```

### Accessing array values

Proxify is recursive, so you can keep chaining props or indices

```ts
import { proxify } from "rxjs-proxify";
import { of } from "rxjs";

const o = of({ msg: () => ['Hello'] }, { msg: () => ['World'] });
const p = proxify(o);
p.msg()[0].subscribe(console.log);

// equivalent to
// o.pipe(map(x => x?.map()), pluck(0)).subscribe(console.log);
```

## 🀝 Want to contribute to this project?

That will be awesome!

Please create an issue before submiting a PR β€” we'll be able to discuss it first!

Thanks!

## Enjoy πŸ™‚