title: Nested web-components and event handling
body: <p>I'm writing a memory game in javascript. I have made a web-component for the cards, <code>&lt;memory-card&gt;</code> and a web-component to contain the cards and handle the game state <code>&lt;memory-game&gt;</code>. The <code>&lt;memory-card&gt;</code> class contains its image path for when its turned over, the default image to display as the back of the card, its turned state and an <code>onclick</code> function to handle switching between the states and the images.</p>
  
  <p>The <code>&lt;memory-game&gt;</code> class has a setter that receives an array of images to generate <code>&lt;memory-cards&gt;</code> from. What would be the best method to handle updating the game state in the <code>&lt;memory-game&gt;</code> class? Should I attach an additional event listener to the <code>&lt;memory-card&gt;</code> elements there or is there a better way to solve it? I would like the <code>&lt;memory-card&gt;</code> elements to only handle their own functionality as they do now, ie changing images depending on state when clicked. </p>
  
  <p><strong>memory-game.js</strong></p>
  
  <pre><code>class memoryGame extends HTMLElement {
    constructor () {
      super()
      this.root = this.attachShadow({ mode: 'open' })
      this.cards = []
      this.turnedCards = 0
    }
  
    flipCard () {
      if (this.turnedCards &lt; 2) {
        this.turnedCards++
      } else {
        this.turnedCards = 0
        this.cards.forEach(card =&gt; {
          card.flipCard(true)
        })
      }
    }
  
    set images (paths) {
      paths.forEach(path =&gt; {
        const card = document.createElement('memory-card')
        card.image = path
        this.cards.push(card)
      })
    }
  
    connectedCallback () {
      this.cards.forEach(card =&gt; {
        this.root.append(card)
      })
    }
  }
  
  customElements.define('memory-game', memoryGame)
  </code></pre>
  
  <p><strong>memory-card.js</strong></p>
  
  <pre><code>class memoryCard extends HTMLElement {
    constructor () {
      super()
      this.root = this.attachShadow({ mode: 'open' })
      // set default states
      this.turned = false
      this.path = 'image/0.png'
      this.root.innerHTML = `&lt;img src="${this.path}"/&gt;`
      this.img = this.root.querySelector('img')
    }
  
    set image (path) {
      this.path = path
    }
  
    flipCard (turnToBack = false) {
      if (this.turned || turnToBack) {
        this.turned = false
        this.img.setAttribute('src', 'image/0.png')
      } else {
        this.turned = true
        this.img.setAttribute('src', this.path)
      }    
    }
  
    connectedCallback () {
      this.addEventListener('click', this.flipCard())
    }
  }
  
  customElements.define('memory-card', memoryCard)
  </code></pre>
  
  <p><strong>implementing the custom event after Supersharp's answer</strong></p>
  
  <p><strong>memory-card.js (extract)</strong></p>
  
  <pre><code>connectedCallback () {
      this.addEventListener('click', (e) =&gt; {
        this.flipCard()
        const event = new CustomEvent('flippedCard')
        this.dispatchEvent(event)
      })
    }
  </code></pre>
  
  <p><strong>memory-game.js (extract)</strong></p>
  
  <pre><code>  set images (paths) {
      paths.forEach(path =&gt; {
        const card = document.createElement('memory-card')
        card.addEventListener('flippedCard', this.flipCard.bind(this))
        card.image = path
        this.cards.push(card)
      })
    }
  </code></pre>