-1

Description & Goal

I have a list with items and clicking on an item shows a detail view, shows a close button and add the eventlistener for closing this item to the button. By clicking on this button the detail view should be closed and the eventlistener should be removed.

I can't use an anonymous function because removing won't work with it (See here and here).

Problem

Removing doesn't work.

Code

export default class ToggleDetails {
  constructor(jobAdId) {
    this.jobAdId = jobAdId
    this.opened = false
  }

  toggle() {
    const jobAdContainer = document.getElementById(this.jobAdId)
    // doing some other css manipulation for the detail view
    this.handleCloseButton()
  }

  handleCloseButton() {
    const closeButton = document.getElementById('uh-job-detail-close-button')

    const $this = () => {
      this.toggle()
    }

    if (this.opened === true) {
      closeButton.classList.remove('uh-job-detail-close-button-show')
      closeButton.removeEventListener('click', $this)
      this.opened = false
    } else {
      closeButton.classList.add('uh-job-detail-close-button-show')
      closeButton.addEventListener('click', $this)
      this.opened = true
    }
  }
}

HTML structure enter image description here

"Solution"/Workaround

I solved it, by cloning and replacing the button with itself. The clone doesn't have the eventlisteners (Thanks to this post)

handleCloseButton () {
    const closeButton = document.getElementById(
      'uh-job-detail-close-button')
      
    closeButton.classList.toggle('uh-job-detail-close-button-show')

    if (this.opened === true) {
      const elClone = closeButton.cloneNode(true)
      closeButton.parentNode.replaceChild(elClone, closeButton)
      this.opened = !this.opened
    } else {
      closeButton.addEventListener('click',
        () => { this.toggle() })
      this.opened = !this.opened
    }
  }
leonp5
  • 305
  • 7
  • 23
  • Why do you want to add and remove the listener? Just delegate from the closets static container. This sounds like an X/Y problem – mplungjan Nov 26 '20 at 08:35
  • Also `this.opened = !this.opened;closeButton.classList.toggle('uh-job-detail-close-button-show',this.opened); ` – mplungjan Nov 26 '20 at 08:38
  • Thanks for your comment. I thought this would be the best way, to toggle different detail views with the same button. Can you clarify, what you mean by `delegate from the closest static containr` ? – leonp5 Nov 26 '20 at 08:38
  • Firstly, where is the close button. If inside the `this` details, then no need to ever remove it Secondly: something like this (not knowing your HTML) `document.getElementById("someContainer").addEventListener("click",function(e) { const tgt = e.target; if tgt.classList.contains("close")) tgt.closest("div").classList.remove("show") })` – mplungjan Nov 26 '20 at 08:42
  • Added the HTML structure to the question. Maybe it helps to understand my problem. Toggling the css is not the problem. Removing the eventlistener is the problem in my case. – leonp5 Nov 26 '20 at 08:59
  • Please post CODE, not PICTURES of code. And I ask again: WHY do you feel the need to remove an event listener from a button that might be needed again? And why do you need the event listener on the button and not on the container – mplungjan Nov 26 '20 at 09:09
  • This HTML is build by a javscript function dynamically. So i can't post the HTML code. And i dont think, that the CSS is important for my question. I want the eventlistener on this one button, because this one button should be able to close different containers. The user can open one container and close it with the button. Open another container and close it with this button and so on. – leonp5 Nov 26 '20 at 09:18
  • So it IS an X/Y question. If you post the actual example divs from view source and the rules for clicking and what that clicks opens, then all we need is to figure out which container the button needs to access. I see absolutely no need to REMOVE an event listener, just save which container is being acted on at the time – mplungjan Nov 26 '20 at 09:29
  • I updated my question. The toggle function gets the id from the div and when you look down at the comments from my conversation with `sbgib` i think i tried exactly what your are proposing (if i understand you right). But it leads to inconsistent behaviour. Each container has is own toggle function. Maybe there is the problem of my whole logic. Thats the reason, why i want to add and remove the listener. – leonp5 Nov 26 '20 at 10:24
  • I am quite sure your logic is flawed and you need workarounds to perform what you want. I strongly suggest you do NOT remove event listeners but instead make them undersstand what they need to do – mplungjan Nov 26 '20 at 10:31

1 Answers1

0

Try using a named function and passing the value of this into toggle:

export default class ToggleDetails {
  constructor(jobAdId) {
    this.jobAdId = jobAdId
    this.opened = false
  }

  toggle(t) {
    // doing some other css manipulation for the detail view
    t.handleCloseButton()
  }

  handleCloseButton() {
    const closeButton = document.getElementById('uh-job-detail-close-button')

    let listenerToggle = () => {
       this.toggle(this);
    };

    if (this.opened === true) {
      closeButton.classList.remove('uh-job-detail-close-button-show')
      closeButton.removeEventListener('click', listenerToggle)
      this.opened = false
    } else {
      closeButton.classList.add('uh-job-detail-close-button-show')
      closeButton.addEventListener('click', listenerToggle)
      this.opened = true
    }
  }
}
sbgib
  • 5,580
  • 3
  • 19
  • 26
  • Thanks for your answer :) I modified the question. The `toggle` function needs the id from the `jobAdContainer`. So how can i pass the id through it in the eventlistener? – leonp5 Nov 26 '20 at 08:57
  • The id is a property of the class defined in the contructor, not an argument passed into `toggle`, so I think it should still work. I've updated this answer to reflect your edit. – sbgib Nov 26 '20 at 09:15
  • Thanks, but the console throws `jobAdContainer is null`. – leonp5 Nov 26 '20 at 09:20
  • Ok, so if `toggle` doesn't already recognise `this`, then passing in the value may be the way to go. I've updated the answer again, see if that works :) – sbgib Nov 26 '20 at 09:48
  • Thanks for your patience :) Behavior now: Open one `jobAdContainer` and close it with the button. Open another `jobAdContainer` and when i close the second `jobAdContainer` with the button the first opens. So Removing doesn't seem to work. Maybe i have to change the whole logic or simply understand what `mplungjan` commented on top ;-) – leonp5 Nov 26 '20 at 10:00
  • I think that is because of this line: `const jobAdContainer = document.getElementById(this.jobAdId)`. I would recommend removing this from the class and instead setting this value to a new variable if you need it, e.g. `var element = document.getElementById(classInstance.jobAdId)`. – sbgib Nov 27 '20 at 07:52