公式ホームページのIntro to Vue 3クラス10 (Communicating Events)

# 10. Communicating Events

>クラス https://www.vuemastery.com/courses/intro-to-vue-3/communicating-events-vue3

VS Codeから該当フォルダを選択して、開きます。その後に、配下のgit部分をクリックして、ブランチをL10-startへ入れ替えてください。

>ブランチ切り替え方法 https://qiita.com/phjg81/items/e6695eb2334d9297a318

今日のポイントはcomponents内部から発生したイベントを親エレメントへ通知することです。
クラス9ではcartを外に置いて、制御してまいたが、それがProductDisplayの内部にあり、それぞれの商品から、「add-to-cart」されるようにやります。
その方法は「this.$emit()」をcomponents内部実装することにより、可能です。

```javascript:ProductDisplay.js：this.$emit()追記して親にて発生したadd-to-cartイベントとつなぐ
app.component('product-display', {
    template: 
      ...
     ,
    data() {
      ...
    },
    methods: {
        addToCart() {
            this.$emit('add-to-cart')
            // this.cart += 1
        },
        ...
    },
    computed: {
        ...
    }
  })
```

```javascript:main.js：updateCart追記
const app = Vue.createApp({
    data() {
        return {
            cart: 0,
            premium: true
        }
    },
    methods: {
        updateCart() {
            this.cart += 1
        }
    }
})

```

```html:index.html：@add-to-cart追記してupdateCartを実行
      <product-display :premium="premium" @add-to-cart="updateCart"></product-display>

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516328/e687e70d-c0ec-9062-9e84-b6b8820cafc8.png)

cartに各製品をそれぞれ追加して見ます。

```javascript:main.js：cartを配列へ変更
const app = Vue.createApp({
    data() {
        return {
            cart: [],
            premium: true
        }
    },
    methods: {
        updateCart(id) {
            this.cart.push(id)
        }
    }
})

```

```javascript:ProductDisplay.js：選択されたidを渡す
app.component('product-display', {
    template: 
      ...
     ,
    data() {
      ...
    },
    methods: {
        addToCart() {
            this.$emit('add-to-cart', this.variants[this.selectedVariant].id)
            // this.cart += 1
        },
        ...
    },
    computed: {
        ...
    }
  })
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2516328/fe096cca-95c3-bc8f-b34a-54eee430eb2f.png)

実際のidが表示されて、宜しくなさそうなので、合計のみを表示するようにやりましょう。

```html:index.html：@add-to-cart追記してupdateCartを実行
      <div class="cart">Cart({{ cart.length }})</div>

```

今回の課題はproduct-display Components内部にボタンを一個追加して、そのボタンを押下すると、cartから1ずつ減らす機能を作成して見ましょう。

<details>
<summary>課題確認</summary><div>

```javascript:ProductDisplay.js：removeFromCart追加
app.component('product-display', {
  props: {
    ...
  },
  template: 
  /*html*/
  `<div class="product-display">
    ...
        <button 
          class="button" 
          :class="{ disabledButton: !inStock }" 
          :disabled="!inStock" 
          v-on:click="addToCart">
          Add to Cart
        </button>
        <!-- solution -->
        <button 
          class="button" 
          @click="removeFromCart">
          Remove Item
        </button>
      </div>
    </div>
  </div>`,
  data() {
    return {
        ...
    }
  },
  methods: {
      addToCart() {
          // solution
          this.$emit('add-to-cart', 'A', this.variants[this.selectedVariant].id)
      },
      // solution
      removeFromCart() {
        this.$emit('remove-from-cart', 'D', this.variants[this.selectedVariant].id)
     },
      updateVariant(index) {
          this.selectedVariant = index
      }
  },
  computed: {
      ...
  }
})

```

```javascript:main.js：分岐追記
const app = Vue.createApp({
    data() {
        return {
            cart: [],
            premium: true
        }
    },
    methods: {
        // solution
        updateCart(type, id) {
            if(type=='A') {
                this.cart.push(id)
            } else if(type=='D') {
                const index = this.cart.indexOf(id)
                if (index > -1) {
                    this.cart.splice(index, 1)
                }
            }
        }
    }
})

```

```html:index.html：remove-from-cartイベント追記
      <product-display :premium="premium" @add-to-cart="updateCart" @remove-from-cart="updateCart"></product-display>
```

公式ホームページの内容は以下のものです。

```javascript:ProductDisplay.js：removeFromCart追加
app.component('product-display', {
  props: {
    ...
  },
  template: 
  /*html*/
  `<div class="product-display">
    ...
        <button 
          class="button" 
          :class="{ disabledButton: !inStock }" 
          :disabled="!inStock" 
          v-on:click="addToCart">
          Add to Cart
        </button>
        <!-- solution -->
        <button 
        class="button" 
        :class="{ disabledButton: !inStock }" 
        :disabled="!inStock" 
        @click="removeFromCart">
        Remove Item
      </button>
      <!-- solution -->
      </div>
    </div>
  </div>`,
  data() {
    ...
  },
  methods: {
      addToCart() {
          this.$emit('add-to-cart', this.variants[this.selectedVariant].id)
      },
      // solution
      removeFromCart() {
        this.$emit('remove-from-cart', this.variants[this.selectedVariant].id)
      },
      // solution
      updateVariant(index) {
          this.selectedVariant = index
      }
  },
  computed: {
      ...
  }
})

```

```javascript:main.js：removeById追加
const app = Vue.createApp({
    data() {
        return {
            cart: [],
            premium: true
        }
    },
    methods: {
        updateCart(id) {
            this.cart.push(id)
        },
        // solution
        removeById(id) {
            const index = this.cart.indexOf(id)
                if (index > -1) {
                    this.cart.splice(index, 1)
                }
        }
        // solution
    }
})

```

```html:index.html：remove-from-cartイベント追記
      <product-display 
        :premium="premium" 
        @add-to-cart="updateCart"
        @remove-from-cart="removeById"> <!-- solution -->
      </product-display>
```

</div>
</details>