stimulusreflex / stimulus_reflex

Build reactive applications with the Rails tooling you already know and love.
https://docs.stimulusreflex.com
MIT License
2.28k stars 172 forks source link

Cannot read property 'removeEventListener' of undefined after updating to 3.1.0 #151

Closed ghost closed 4 years ago

ghost commented 4 years ago

Bug Report

NOTE: I am no JS pro, so I may perfectly well be missing something obvious.

Describe the bug

After updating my code from stimulus_reflex 3.0.0 to 3.1.0 in both the gem & node, I am getting errors on a page that used to work.

To Reproduce

I do not have a clean repro case yet, just stack trace that appears to be entirely in the JS:

TypeError: can't access property "removeEventListener", socket is undefined consumer.js:38
    registerConsumer consumer.js:38
    createSubscription stimulus_reflex.js:78
    register stimulus_reflex.js:191
    StimulusReflexController stimulus_reflex.js:214
    construct self-hosted:1871
    Controller definition.js:43
    Context context.js:9
    fetchContextForScope module.js:55
    connectContextForScope module.js:37
    scopeConnected router.js:100
    elementMatchedValue scope_observer.js:55
    tokenMatched value_list_observer.js:54
    tokenMatched token_list_observer.js:82
    tokensMatched token_list_observer.js:69
    forEach self-hosted:225
    tokensMatched token_list_observer.js:68
    elementMatchedAttribute token_list_observer.js:49
    elementMatched attribute_observer.js:59
    addElement element_observer.js:151
    processAttributeChange element_observer.js:84
    processMutation element_observer.js:67
    processMutations element_observer.js:60
    mutationObserver element_observer.js:12
    (Async: MutationCallback)
    ElementObserver element_observer.js:11
    AttributeObserver attribute_observer.js:9
    TokenListObserver token_list_observer.js:8
    ValueListObserver value_list_observer.js:7
    ScopeObserver scope_observer.js:11
    Router router.js:10
    Application application.js:159
    start application.js:163
    js index.js:8
    Webpack 5

The Stimulus Reflex code on the page is very close to the Gravatar example in Expo (just modified to use Libravatar instead). No custom controller involved.

Versions

StimulusReflex

External tools

Browser

(Repros in both)

hopsoft commented 4 years ago

Thanks for the bug report. This is interesting. What client side event is your reflex wired up to?

ghost commented 4 years ago

It's a pretty direct clone of https://expo.stimulusreflex.com/demos/gravatar so it's on input

HAML source code:

  .columns
    .column
      = f.input :email, hint: f.object.new_record? ? t('.email.hint') : nil, input_html: { data: { reflex: 'input->LibravatarReflex#perform' } }
    .column
      .span.image.is-64x64= image_tag(@libravatar_image_url || '')
hopsoft commented 4 years ago

Does this error happen consistently or only some of the time? Also, what version of ActionCable are you using?

Note that I just deployed the expo site using StimulusReflex 3.1.0 and can't seem to replicate this error (locally or on the Heroku deployment).

http://expo.stimulusreflex.com/demos/gravatar

ghost commented 4 years ago

It's consistently for me, ActionCable is at 6.0.2.2

Let me see if I can come up with a repro in a fresh project. If it doesn't repro on the Expo project it seems likely this is something squirrelly that I'm doing.

hopsoft commented 4 years ago

OK. We need to be more defensive around this section of code (that's providing a non-essential bit of functionality). I'll work on a patch release today and try to ship it tomorrow. https://github.com/hopsoft/stimulus_reflex/blob/master/javascript/consumer.js#L36-L46

Thanks again.

patmisch commented 4 years ago

I've been pulling my hair out all day trying to figure this out as well. Assumed it was something I was doing wrong since this is my first time using ActionCable.

hopsoft commented 4 years ago

Sorry for any confusion. Please use 3.0.0 while waiting for the patch. 🙏

bbugh commented 4 years ago

If it helps, I also reported this issue and have easily reproducible steps in #153.

ghost commented 4 years ago

3.1.2 fixed the problem for me and provided enough additional info for me to figure out what I did wrong, so THANKS.

For anyone else who hits this and runs across this issue: with 3.1.2, on page load I get StimulusReflex was unable to register the ActionCable consumer. Don't worry, everything should still work. Things still didn't work when triggering the actual reflex from the UI, but now the console (properly) informs me

Error invoking action "input->stimulus-reflex#__perform"

 The ActionCable connection is not open! `this.isActionCableConnectionOpen()` must return true before calling `this.stimulate()` 

And that in turn finally led me to realize that the problem does indeed trace back to my own bad code. The issue in this case is that I have implemented authentication in ApplicationCable::Connection#connect but this particular reflex appears on a page outside of the application's authentication context. So ActionCable is doing exactly what I told it to do and not connecting, and StimulusReflex is quite properly refusing to act without any way to talk to the server.