# Groups and propagation

When you register multiple handlers with conflicting filters,
only the one registered the first will be executed, to avoid
handling the same update twice.

This is sometimes undesirable, and to handle these you can use
either [handler groups](#groups), or [propagation symbols](#propagation)

::: tip
You can also use a [child Dispatcher](children.html). In this page, however,
it is assumed that all handlers are registered to one dispatcher.
:::

## Groups

Your first option to handle the same update multiple times is by
using a separate handler group.

Handler groups are identified with a single number (group `0` is the
default group) and are processed within the same dispatcher one-by-one
in order (`..., -2, -1, 0, 1, 2, ...`).

For example, consider the following code

```ts
dp.onNewMessage(
  filters.or(filters.text, filters.sticker),
  async (msg) => {
    console.log('Text or sticker')
  }
)

dp.onNewMessage(
  filters.text,
  async (msg) => {
    console.log('Text only')
  }
)
```

In this code, the second handler will never be executed, because
the first one handles `text` messages as well.

To make the Dispatcher execute the second handler, you can
register it to a different group:

```ts
dp.onNewMessage(
  filters.text,
  async (msg) => {
    console.log('Text only')
  },
  1
)
```

In this case, this handler will be executed *after* the first one.
Alternatively, you can pass a negative number to make the second
handler execute *before* the first one:

```ts
dp.onNewMessage(
  filters.text,
  async (msg) => {
    console.log('Text only')
  },
  -1
)
```

Group can also be set using `addUpdateHandler`:

```ts
dp.addUpdateHandler({ ... }, 1)
```

## Propagation

To customize the behaviour even further, you can use propagation symbols
that `@mtcute/dispatcher` exports in `PropagationAction` enum.

### Stop propagation

To prevent the update from being handled by any other handlers
within the same dispatcher, you can use `PropagationAction.Stop`:

```ts
dp.onNewMessage(
  filters.or(filters.text, filters.sticker),
  async (msg) => {
    console.log('Text or sticker')

    return PropagationAction.Stop
  }
)

dp.onNewMessage(
  filters.text,
  async (msg) => {
    console.log('Text only')
  },
  1
)
```

In the above code, second handler *will not* be executed even though it is
in a separate group.

This will not, however, prevent the handlers from a
[child Dispatcher](children.html) to be executed.

### Stop children propagation

A bit ahead of ourselves, since we haven't covered child
Dispatchers yet, but the idea is pretty simple.

`PropagationAction.StopChidlren` is very similar to the previous one, but also
prevents the handlers from child dispatchers to be executed:

```ts
dp.onNewMessage(
  filters.or(filters.text, filters.sticker),
  async (msg) => {
    console.log('Text or sticker')

    return PropagationAction.StopChidlren
  }
)

const dp1 = new Dispatcher()
dp.addChild(dp1)

dp1.onNewMessage(
  filters.text,
  async (msg) => {
    console.log('Text only')
  }
)
```

In the above code, second executor will not be called, even though
it is in a child dispatcher.

### Continue propagation

As an alternative to [groups](#groups), you can use `PropagationAction.Continue`
symbol. It makes the dispatcher continue propagating this update within
the same group even though some handler from that group was already executed:

```ts
dp.onNewMessage(
  filters.or(filters.text, filters.sticker),
  async (msg) => {
    console.log('Text or sticker')

    return PropagationAction.Continue
  }
)

dp.onNewMessage(
  filters.text,
  async (msg) => {
    console.log('Text only')
  }
)
```

In the above code, the second dispatcher will be called for text messages
even though the first one also matches them.

Note that `Continue` only works within the same handler group.

## Raw updates

As mentioned earlier, raw updates are handled independently of parsed
updates, and they have their own groups and propagation chain.

This means that in the following example both handlers will be called,
despite returning `Stop` action:

```ts
dp.onNewMessage(() => {
  return PropagationAction.Stop
})

dp.onRawUpdate(
  (cl, upd) => upd._ === 'updateNewMessage',
  () => { ... }
)
```
