Multi-Store DOM Events (Angular)
Tags: angular, rxjs, reactive, stateadapt
Published: 2022-07-13 09:17:23

---
title: Multi-Store DOM Events (Angular)
published: true
description: Easily guaranteeing consistency with multi-store DOM events.
tags: angular, rxjs, reactive, stateadapt
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tyejoi7mpcgna7sgc2mw.png
# zoomed out: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8g00kow5rhv3wbai90qo.png
series: Progressive Reactivity in Angular
---

> This series explores how we can keep our code declarative as we adapt our features to progressively higher levels of complexity.

## Level 6:  Multi-Store DOM Events

Sometimes multiple stores need to react to a single DOM event. Let's say we have a button in our template that sets all colors in all stores to black. If it weren't for [Rule 2](https://dev.to/this-is-angular/simple-derived-state-progressive-reactivity-in-angular-48oe), we might write a click handler like this:

```typescript
  setAllToBlack() {
    // `set` is a state change that should come by default with every adapter
    this.favoriteStore.set(['black', 'black', 'black']);
    this.dislikedStore.set(['black', 'black', 'black']);
    this.neutralStore.set(['black', 'black', 'black']);
}
```

It is very common for developers to write callback functions so they can dispatch multiple actions for a single event. This is the imperative style and unsurprisingly is often accompanied by forgotten updates and inconsistent state. The total number of imperative statements is 4 now, instead of just the 1 from the template, and we now see 3 "events" in Devtools dispatched back-to-back, which makes it harder to understand what actually happened that caused these changes. 

If you are using NgRx or NGXS, keep your code reactive and dispatch exactly 1 action for each event, and have all reducers/states/stores react to that single action. This keeps our event sources and stores as declarative as possible, and reduces repetition.

So let's add this state change to the adapter:
```typescript
    setAllToBlack: state => ['black', 'black', 'black'],
```

Our goal with the button is to push the least amount of data possible to a single place in TypeScript. Since 3 stores need the data, we need to create an independent place to push the event to, and have all stores react to _that_. We also want to annotate that event source. So let's have something like 

```typescript
  blackout$ = new Source('[Colors] Blackout');
```

All the stores can connect this source and state change like this:

```typescript
    setAllToBlack: this.blackout$,
```

Here's the whole thing with these changes highlighted:

```diff
export class ColorsComponent {
  adapter = createAdapter<string[]>({ // For type inference
    changeColor: (colors, [newColor, index]: [string, number]) =>
      colors.map((color, i) => i === index ? newColor : color),
+   setAllToBlack: state => ['black', 'black', 'black'],
    selectors: {
      colors: state => state.map(color => ({
        value: color,
        name: color.charAt(0).toUpperCase() + color.slice(1),
      })),
    },
  });

  initialState = ['loading', 'loading', 'loading'];
+
+ blackout$ = new Source<void>('[Colors] Blackout');

  favoriteColors$ = this.colorService.fetch('favorite').pipe(
    toSource('[Favorite Colors] Received'),
  );
  favoriteStore = createStore(
    ['colors.favorite', this.initialState, this.adapter], {
    set: this.favoriteColors$,
+   setAllToBlack: this.blackout$,
  });

  dislikedColors$ = this.colorService.fetch('disliked').pipe(
    toSource('[Disliked Colors] Received'),
  );
  dislikedStore = createStore(
    ['colors.disliked', this.initialState, this.adapter], {
    set: this.dislikedColors$,
+   setAllToBlack: this.blackout$,
  });

  neutralColors$ = this.colorService.fetch('neutral').pipe(
    toSource('[Neutral Colors] Received'),
  );
  neutralStore = createStore(
    ['colors.neutral', this.initialState, this.adapter], {
    set: this.neutralColors$,
+   setAllToBlack: this.blackout$,
  });
}
```

Here's how it looks:

![Color Picker—Multi-Store Dom Events](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qetih63zjxm3aslg7896.png)

[StackBlitz](https://stackblitz.com/edit/angular-ivy-cwnz5p?file=src%2Fapp%2F6-dom-sources.component.ts)