4

I am trying to get user's input from Shadow DOM with addEventListener, but I don't get any response, any error. References to the elements work correctly, so console.log(input) prints out the correct element. The same code works perfectly fine without shadow DOM but I have to include it in my project. This is my code (these events are just for checking of course):

const template = document.createElement('template')
template.innerHTML = /* html */`
<div id="username">
  <p>Please choose your username!</p>
  <input id="username_input" type="text" placeholder="enter username">
  <button>Ok</button>
</div>
`
/**
 * @class Quiz
 * @extends {window.HTMLElement}
 */
export class Quiz extends window.HTMLElement {
  constructor () {
    super()
    this.attachShadow({ mode: 'open' })
    this.shadowRoot.appendChild(template.content.cloneNode(true))
  }

  getUserName () {
    const button = this.shadowRoot.querySelector('button')
    const inputUname = this.shadowRoot.querySelector('#username input')
    console.log(button)
    button.addEventListener('click', event => console.log('badum tss'))
    inputUname.addEventListener('input', event => console.log('badums tss'))
  }
}
window.customElements.define('user-name', Quiz)

app.js code:

import { Quiz } from './quiz.js'

var x = new Quiz()
x.getUserName()

html:

<!doctype html>
<html lang="">
    <head>
        <meta charset="utf-8">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <script type="module" src="js/app.js"></script>
        <link rel="stylesheet" href="css/style.css">
    </head>
    <body>
        <user-name></user-name>
        <script nomodule src="build.js"></script>
    </body>
</html>
Maria
  • 51
  • 5
  • 1) I don't see any code that actually calls `getUserName()`, so your event listeners are never attached, 2) 'input' isn't a native event. It _can_ be a custom event, but you need to define it, and have some code broadcast to it. I don't see code for either of these things. – CrayonViolent Dec 10 '19 at 22:19
  • Without more info, here is something that might point you in the right direction. Some of it isn't relvant to your question, but the shadow dom code examples may help. https://stackoverflow.com/questions/55139670/analytics-script-is-not-sending-data-from-shadow-dom/55204969#55204969 – CrayonViolent Dec 10 '19 at 22:22
  • Yes, sorry, I only copied this module. I have updated the question. Ok, but why doesn't 'click' work? And this code works perfectly fine if I don't use Shadow DOM, so I am a bit lost... – Maria Dec 11 '19 at 04:04

1 Answers1

1

The problem is quite simple. Your code actually creates two <user-name>s.

One is statically created in html:

<user-name></user-name>

The other is dynamically created by javascript:

var x = new Quiz()

The dynamic one is never attached to the document, so you can only see the static one on the page. Since you only call getUserName() on the dynamic one, the click and input listeners are never added to the static one. That's why you didn't get any response.

I would suggest that you put addEventListener() in the constructor, then the static one should function normally.

Microloft
  • 345
  • 1
  • 7
  • Yes, that worked, thank you! Is it possible to fix it somehow so that it's not too much code in the constructor? – Maria Dec 12 '19 at 13:12
  • You mean that you want to have as few lines of code as possible in the constructor? You can keep `addEventListener()` in the original place, and just explicitly call `this.getUserName()` in the constructor, although I don't see any benefit of that. – Microloft Dec 12 '19 at 13:27