I’m building a chatroom alongside Actioncable and was stumped on how I can implement a typing indicator, along the lines of “Taylor started typing…”. I’ve managed to get it setup in with a Stimulus controller to listen when someone starts typing in the input field, and broadcast across the channel.
initChannel() {
this.startedTyping = this.startedTyping.bind(this) this.inputTarget.addEventListener('keydown', this.startedTyping) this.stoppedTyping = this.stoppedTyping.bind(this) this.inputTarget.addEventListener('blur', this.stoppedTyping)
}
startedTyping() {
this.channel.perform('typing', { chatroom_id: chatroom_id, typing: 'started' } )
}
This works fine and dandy but it results in ActionCable broadcasting a message for every single keystroke. It’s not bad, and not that it doesn’t work but it seems that it’s overkill to perform this for every keystroke, rather broadcast across ActionCable only once. Looking at Basecamp, there is one broadcast when a person begins typing, and one when they stop - they toggle the typing indicator based on these actions.
18:43:36 web.1 | ChatroomsChannel#typing({“chatroom_id”=>“2”, “typing”=>“started”})
18:43:36 web.1 | [ActionCable] Broadcasting to chatrooms:2: {:typing=>“started”, :user_name=>“Taylor Cooney”, :chatroom_id=>“2”}
18:43:36 web.1 | ChatroomsChannel transmitting {“typing”=>“started”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:36 web.1 | ChatroomsChannel transmitting {“typing”=>“started”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:36 web.1 | ChatroomsChannel#typing({“chatroom_id”=>“2”, “typing”=>“started”})
18:43:36 web.1 | [ActionCable] Broadcasting to chatrooms:2: {:typing=>“started”, :user_name=>“Taylor Cooney”, :chatroom_id=>“2”}
18:43:36 web.1 | ChatroomsChannel transmitting {“typing”=>“started”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:36 web.1 | ChatroomsChannel transmitting {“typing”=>“started”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:36 web.1 | ChatroomsChannel#typing({“chatroom_id”=>“2”, “typing”=>“started”})
18:43:36 web.1 | [ActionCable] Broadcasting to chatrooms:2: {:typing=>“started”, :user_name=>“Taylor Cooney”, :chatroom_id=>“2”}
18:43:36 web.1 | ChatroomsChannel transmitting {“typing”=>“started”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:36 web.1 | ChatroomsChannel transmitting {“typing”=>“started”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:36 web.1 | ChatroomsChannel#typing({“chatroom_id”=>“2”, “typing”=>“started”})
18:43:36 web.1 | [ActionCable] Broadcasting to chatrooms:2: {:typing=>“started”, :user_name=>“Taylor Cooney”, :chatroom_id=>“2”}
18:43:36 web.1 | ChatroomsChannel transmitting {“typing”=>“started”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:36 web.1 | ChatroomsChannel transmitting {“typing”=>“started”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:37 web.1 | ChatroomsChannel#typing({“chatroom_id”=>“2”, “typing”=>“stopped”})
18:43:37 web.1 | [ActionCable] Broadcasting to chatrooms:2: {:typing=>“stopped”, :user_name=>“Taylor Cooney”, :chatroom_id=>“2”}
18:43:37 web.1 | ChatroomsChannel transmitting {“typing”=>“stopped”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)
18:43:37 web.1 | ChatroomsChannel transmitting {“typing”=>“stopped”, “user_name”=>“Taylor Cooney”, “chatroom_id”=>“2”} (via streamed from chatrooms:2)