hotwired / hotwired/stimulus

`connect` not picking up initial values of input elements (browser 'back' button)

Open
#328 13 comments 10 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
13.1k
Forks
441
PR merge metrics
No merged PRs in 30d

Description

Hi there!

We stumbled upon unexpected behavior when using connect.

Scenario:

  1. We have a page with radio buttons
  2. The user selects a radio button
  3. The user submits the form
  4. The user uses the back button in her browser
  5. Stimulus' connect does not recognize the selected radio button

GIF of the behavior:

screengrab-20200907-1325

image

Stimulus controller
export default class extends Controller {
  static targets = ["buttons"]

  initialize() {
    console.group('initialize')
    console.log('target', this.buttonsTarget)
    console.log('selected radio button', this.buttonsTarget.querySelector(":scope input:checked"))
    console.groupEnd()
  }

  connect() {
    console.group('connect')
    console.log('target', this.buttonsTarget)
    console.log('selected radio button', this.buttonsTarget.querySelector(":scope input:checked"))
    console.groupEnd()

    let self = this
    setTimeout(function() {
      console.group('connect with timeout')
      console.log('target', self.buttonsTarget)
      console.log('selected radio button', self.buttonsTarget.querySelector(":scope input:checked"))
      console.groupEnd()
    }, 1)
  }

  loadEvent() {
    console.group('load@window')
    console.log('target', this.buttonsTarget)
    console.log('selected radio button', this.buttonsTarget.querySelector(":scope input:checked"))
    console.groupEnd()
  }
}
View
<%= form_tag '/examples' do %>
  <div data-controller="radios" data-target="radios.buttons" data-action="load@window->radios#loadEvent">
    <div><%= radio_button_tag 'radios', 'a' %> a</div>
    <div><%= radio_button_tag 'radios', 'b' %> b</div>
  </div>

  <%= submit_tag %>
<% end %>

A demo Rails project is available on https://github.com/phylor/stimulus-connect-back-button.

Expected behavior:

The code below should evaluate to the selected radio button. It is null instead.

connect() {
  this.buttonsTarget.querySelector(":scope input:checked")
}

Workaround:

Use setTimeout within connect:

let self = this
setTimeout(function() {
  self.buttonsTarget.querySelector(":scope input:checked")
}, 1)

Browsers:

  • Chrome/qutebrowser: unexpected behavior, setTimeout workaround required
  • Firefox: seems to work as expected, even in initialize the selected radio button is found

I have to admit that I managed to get the expected behavior in Chrome as well. But really really seldom. Could be a race condition?

Questions

  • Is this just a bug in Chrome?
  • Is there something Stimulus could do to remedy the workaround?
  • Is there an entire different solution for this problem?

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue names no repository files; start with the included Stimulus controller's connect() and reproduce the radio-button back-navigation case in Chrome and Firefox using the linked demo Rails project. Compare initialization, connect(), load@window, and the setTimeout workaround, then determine whether a Stimulus change is possible and verify the behavior with a focused regression test if an affected entry point is identified.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
frontend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.