Skip to content

Instantly share code, notes, and snippets.

@scottbarrow
Forked from leastbad/README.md
Created October 28, 2020 15:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save scottbarrow/2fb920816a060f48d158756a4e7b854f to your computer and use it in GitHub Desktop.
Save scottbarrow/2fb920816a060f48d158756a4e7b854f to your computer and use it in GitHub Desktop.
stimulus-websocket preview

This controller can be put on body or any other element.

  1. Adds a websocket accessor to the element
  2. Controller exposes a connected boolean getter
  3. Controller bails with a warning if no shared consumer is available
  4. Element will have data-action-cable-connected or data-action-cable-disconnected attributes which can be used for CSS selectors
  5. Element will emit action-cable:connected or action-cable:disconnected events only when state is flipping
  6. Errors => Disconnected to keep things simple

I intend to document the navigator.onLine accessor and the window:online/offline events so devs can handle PWA modes.

Seeking feedback on the following:

  • is it within the realm of acceptable to ask people to import consumer and assign it to application.consumer?
  • is it obnoxious for me to call this controller websocket?
  • do you like the event handles and attribute names?
import { Application } from 'stimulus'
import { definitionsFromContext } from 'stimulus/webpack-helpers'
import consumer from '../channels/consumer'
const application = Application.start()
const context = require.context('controllers', true, /_controller\.js$/)
application.load(definitionsFromContext(context))
application.consumer = consumer
import { Controller } from 'stimulus'
export default class extends Controller {
initialize () {
this.element['websocket'] = this
this.consumer = this.application.consumer
this.connection = this.consumer.connection
this.socket = this.connection.webSocket
this.previouslyConnected = false
}
connect () {
if (this.socket) {
this.socket.addEventListener('open', this.connectionOpened)
this.socket.addEventListener('close', this.connectionClosed)
this.socket.addEventListener('error', this.connectionClosed)
this.connected ? this.connectionOpened() : this.connectionClosed()
} else {
console.warn('No shared consumer in scope. Websocket is lonely. 😢')
}
}
disconnect () {
if (this.socket) {
this.socket.removeEventListener('open', this.connectionOpened)
this.socket.removeEventListener('close', this.connectionClosed)
this.socket.removeEventListener('error', this.connectionClosed)
this.connected ? this.connectionOpened() : this.connectionClosed()
}
}
connectionOpened = () => {
this.element.removeAttribute('data-action-cable-disconnected')
this.element.setAttribute('data-action-cable-connected', '')
if (!this.previouslyConnected) this.emit('action-cable:connected')
this.previouslyConnected = true
}
connectionClosed = () => {
this.element.removeAttribute('data-action-cable-connected')
this.element.setAttribute('data-action-cable-disconnected', '')
if (this.previouslyConnected) this.emit('action-cable:disconnected')
this.previouslyConnected = false
}
emit = event => {
this.element.dispatchEvent(
new CustomEvent(event, {
bubbles: true,
cancelable: false,
detail: {
connection: this.connection
}
})
)
}
get connected () {
return this.consumer ? this.connection.isOpen() : false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment