jimmy
jimmy

Reputation: 445

Custom events in vue.js components

The scenario

Since I have a more complex checkbox I encapsulated it inside a separate component. Inside the template of the parent component I prefer using v-model to bind the value to a variable.

My approach is based on this description (https://v2.vuejs.org/v2/guide/components-custom-events.html#Customizing-Component-v-model) taken from the official documentation.

The problem

When I have two custom-checkbox-elements and I select the last one, the first one inside the DOM will be selected. So it seems, that the first one is consuming the event.

The code

The following snippet illustrates the checkbox component.

<template>
  <div class="checkbox-part">
    <input class="checkbox-part-input" type="checkbox" name="cb" id="cb"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
    <label class="checkbox-part-label" for="cb"
      :class="{ 'checkbox-part-label--checked': checked }"
    >
    <slot name="label"></slot>
    </label>
    <!-- removed for brevetiy -->
  </div>
</template>

<script>
export default {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: {
      type: Boolean,
    }
  }
}
</script>

How can I achieve, that the selected checkbox is updated?

Upvotes: 0

Views: 1835

Answers (2)

jimmy
jimmy

Reputation: 445

As already mentioned in the comments the problem was caused by hard-coded values for id and name inside the CheckboxPart component.

I've added two properties for name and value and inject them into the component as well.

The snippet

<!-- checkbox -->

<template>
  <div class="checkbox-part">
    <input class="checkbox-part-input" type="checkbox" 
      :name="name"
      :id="id"
      v-bind:checked="checked"
      v-on:change="$emit('change', $event.target.checked)"
    >
    <label class="checkbox-part-label" 
      :for="name"
      :class="{ 'checkbox-part-label--checked': checked }"
    >
      <slot name="label"></slot>
    </label>
 
    <!-- removed for brevity -->
 
  </div>
</template>

<script>
  export default {
    model: {
      prop: 'checked',
      event: 'change'
    },
    props: {
      checked: {
        type: Boolean,
      },
      name: {
        type: String,
        required: true
      },
      id: {
        type: String,
        required: true
      }
    }
  }
</script>

<!--- parent component using the one -->

<template>
  <!-- removed for brevity -->
  <!-- ... -->
 <div class="expandable-category-part-social-section">
        <checkbox-part
          v-model="isSocialIntegrationEnabled"
          :id="title + 'social-media'"
          :name="title + 'social-media'"
        >
          <template slot="label">
            <div class="checkbox-part-label-text">Final text comes here...</div>
          </template>
</checkbox-part>
</div>

<!-- ... -->

</template>

Upvotes: 0

zloter
zloter

Reputation: 363

You have name of input hardcoded in component. So you probably render two input with same name ("cb" in this case) I think that you can pass input name and id as props.

This should solve your problem.

Upvotes: 1

Related Questions