Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] DX: due to destruction happening "at any time" / asynchronously, we cannot ergonomically use a conditional on modifier (aka conditional on modifiers are not possible if the condition goes from true to true)) #20647

Open
NullVoxPopuli opened this issue Feb 13, 2024 · 2 comments

Comments

@NullVoxPopuli
Copy link
Contributor

NullVoxPopuli commented Feb 13, 2024

🐞 Describe the Bug

Repro

Code
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { on } from '@ember/modifier';
import * as eModifier from 'ember-modifier';

const lifecycleTest = eModifier.modifier((element, [counter]) => {
  console.log('setting up', counter);
  return () => {
    console.log('removing', counter);
  }
})

class Demo extends Component {
  @tracked count = 0;

  get isEven() {
    return this.count % 2 === 0;
  }

  double = () => {
    console.log('eh?');
    this.count = this.count * 2;
  }
  increment = () => this.count++;

  <template>
    <button 
      {{ (if this.isEven (modifier on 'click' this.double))}}
      {{ (if this.isEven (modifier lifecycleTest this.count))}}
      style="{{if this.isEven "opacity: 1;" "opacity: 0.5; cursor: not-allowed"}}"
    >
      Can only click me when even
    </button>
    <button {{on 'click' this.increment}}>
      Can always click
    </button>

    <div>
      count: {{this.count}}<br>
      isEven: {{this.isEven}}
    </div>
    <br>
  </template>
}

<template>
  <Demo />
</template>

😕 Actual Behavior

teardown happens after setup, but because the same reference to the function that handles the 'click' event is passed, the event listener is removed.

when clicking the double button (can only click me when even),

  • this.isEven is dirtied twice, even though the value remains the same
  • when isEven is dirtied, the modifier destroys itself and re-sets itself up

🤔 Expected Behavior

Event listener is not removed.

🌍 Environment

  • Ember: - 5.5

➕ Additional Context

As a work-around, or maybe ... the solution? we need to create a new reference to the function every time the condition changes so that each addEventListener / removeEventListener pair has a unique reference to the function to handle the event.

atm, I'm trying to figure out how to do that tho

here is a solve:

had to do a custom on modifier that always made its own local ref of the passed function:

Repro/fix

const myOn = eModifier.modifier((element, [eventName, handler]) => {
  let ownRef = (...args) => handler(...args);
  element.addEventListener(eventName, ownRef);
  return () => {
    element.removeEventListener(eventName, ownRef);
  }
})
@NullVoxPopuli NullVoxPopuli changed the title [Bug] DX: due to destruction happening "at any time" / asynchronously, we cannot ergonomically use a conditional on modifier (aka conditional on modifiers are not possible if the condition goes from false to true)) [Bug] DX: due to destruction happening "at any time" / asynchronously, we cannot ergonomically use a conditional on modifier (aka conditional on modifiers are not possible if the condition goes from true to true)) Feb 13, 2024
@NullVoxPopuli
Copy link
Contributor Author

NullVoxPopuli commented Feb 13, 2024

Gonna try to pair with @chancancode on some of this.

I'm getting hung up on @glimmer-workspaces made up testing environment 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant