Skip to content

Latest commit

 

History

History
167 lines (122 loc) · 4.5 KB

use-dispatch.md

File metadata and controls

167 lines (122 loc) · 4.5 KB

useDispatch

Adds a dispatch helper function to emit custom events. Useful to communicate between different controllers.

!> Deprecated: useDispatch() is deprecated. Please use the built-in this.dispatch() function from Stimulus: https://stimulus.hotwired.dev/reference/controllers#cross-controller-coordination-with-events

Migration guide

Because the dispatch() function from Stimulus is very similar, the migration process to the Stimulus version of dispatch() should be fairly simple:

  • remove the useDispatch import
  • remove the useDispatch initializer
  • wrap your payload in a detail object
  import { Controller } from '@hotwired/stimulus'
- import { useDispatch } from 'stimulus-use'

  export default class extends Controller {
    connect() {
-     useDispatch(this)
    }

    add() {
-     this.dispatch('add', { quantity: 1 })
+     this.dispatch('add', { detail: { quantity: 1 } })
    }
  }

Reference

Mixin

useDispatch(controller, options = {})

controller : a Stimulus Controller (usually 'this')

options :

Option Description            Default value               
element The element the event will be emitted from. The controller element
eventPrefix Whether to prefix or not the emitted event. Can be a boolean or a string.
- true prefix the event with the controller identifier item:add
- someString prefix the event with the given string someString:add
- false to remove prefix
true
bubbles Whether the event should bubble. true
cancelable Whether the event is cancelable. true
debug Whether to log debug information. See debug for more information on the debugging tools false

The dispatch function

Once the useDispatch mixin is applied, your controller has a new this.dispatch function available you may use to emit custom events.

dispatch(eventName, detail = {})
Param Description
eventName a mandatory string for the name of the event to emit.
detail A payload object that will be passed through the event and available for the receiver with event.detail

Usage

// item_controller.js
import { Controller } from '@hotwired/stimulus'
import { useDispatch } from 'stimulus-use'

export default class extends Controller {
  connect() {
    useDispatch(this)
  }

  add() {
    // dispatch a custom event item:add
    this.dispatch("add")
  }
}

Bubbling events

The emitted event sent by the dispatch function will bubble up the tree of the DOM. Therefore all parent elements can listen to it directly.

<div data-controller="reciever" data-action="emitter:add->reciever#update">
  <div data-controller="emitter" data-action="click->emitter#add" ></div>
</div>

If both are at the same level or if the reciever controller is even nested within the controller, you should listen to event with @window to catch it.

<div data-controller="reciever" data-action="emitter:add@window->reciever#update"></div>
<div data-controller="emitter" data-action="click->emitter#add" ></div>

Example building a cart counter with the dispatch helper

The HTML markup. See the custom event item:add that the cart controller is listening to

<div data-controller="cart"
     data-action="item:add->cart#refreshTotal"
     data-cart-counter="0">

  <button data-controller="item" data-action="item#add">
    Add
  </button>

  <div>
    <span>No of items : </span>
    <span data-cart-target="counterView">0</span>
  </div>
</div>

The item controller dispatching the event

//item_controller.js
import { useDispatch } from 'stimulus-use'

export default class extends Controller {
  connect() {
    useDispatch(this)
  }

  add() {
    this.dispatch('add', { quantity: 1 })
  }
}

The cart controller receiving the event

//cart_controller.js
import { ApplicationController } from 'stimulus-use'

export default class extends ApplicationController {
  static targets = ['counterView']

  refreshTotal(e) {
    this.counter += e.detail.quantity
    console.log(e.detail.controller) // the emitting item_controller
  }

  renderCounter() {
    this.counterViewTarget.textContent = this.counter
  }

  set counter(value) {
    this.data.set('counter', value)
    this.renderCounter()
  }

  get counter() {
    return this.data.get('counter')
  }
}