Bishwas
Bishwas

Reputation: 203

How can I separate values from reusable checkbox in vuejs?

My question might not match to the problem that I am facing, So, I will explain it in detail here. This is code for SeparateTechnology.vue. I have removed a few methods to make code shorter.

<template>
  <div>
    <div v-for="mss in ms" :key="mss.name">
      <section class="container shadow-box techno-box" v-if="mss.name==selected">
        <p>Review the software criteria below and ensure that you complete each section</p>
        <h4>{{mss.name}}</h4>
        <div class="row shadow-box">
          <div class="col-sm-12 col-lg-6">
            <p>Select all that apply</p>
            <div class="dropdown">
              <input
                v-model.trim="inputValue"
                class="dropdown-input"
                type="text"
                placeholder="Search for your Solution"
              />

              <div class="dropdown-list" v-show="selected">
                <div
                  v-show="itemVisible(item)"
                  v-for="item in mss.subMenu"
                  :key="item"
                  class="dropdown-item"
                >
                  {{ item }}
                  <button
                    class="button button-mini button-dark button-rounded itemLabel"
                    @click="selectSolution(item,mss)"
                  >
                    <i class="icon-line-plus"></i>
                  </button>
                </div>
              </div>
            </div>
          </div>
          <div class="col-sm-12 col-lg-6 rightList">
            <div class="dropdown-list" v-show="selected" v-if="mss.selected_solutions!=''">
              <div v-for="item in mss.selected_solutions" :key="item" class="dropdown-item">
                {{ item }}
                <button
                  class="button button-mini button-dark button-rounded deleteLabel"
                  @click="deleteSelectedItem(item,mss)"
                >
                  <i class="icon-line-minus"></i>
                </button>
              </div>
            </div>
            <div v-else>
              <div class="style-msg errormsg">
                <div class="sb-msg">
                  <i class="icon-remove"></i>You have not selected any solutions.
                </div>
              </div>
            </div>
            <button
              class="button button-mini"
              @click="clearUserOptions(mss)"
              v-if="mss.selected_solutions.length > 1"
            >
              <i class="icon-line-cross"></i>Clear all selection
            </button>
          </div>
          <div style="padding:20px;"></div>
        </div>
        <div class="row">
          <div class="col-sm-12 col-md-3 inputTitle">
            <h5>Don't see it in the list above:</h5>
          </div>
          <input
            class="col-sm-12 col-md-6"
            type="text"
            v-model="value"
            @keydown.enter="getUserSolution(value,mss)"
            placeholder="Enter your solution here.. "
          />
        </div>
        <div style="padding:20px;"></div>
        <div class="row shadow-box">
          <h5
            class="col-sm-12"
          >Identify how the software solution is leveraged within your organization</h5>
          <div
            v-for="item in mss.selected_solutions"
            :key="item"
            class="clearfix col-sm-12 col-md-6"
            style="padding:20px"
          >
            <span v-if="mss.isDifferent=='campaign'">
              <div class="card">
                <h5 class="card-header">{{item}}</h5>
                <CheckBox
                  :groups="campaignMangment"
                  name="campaignMangment"
                  :value="item"
                  classProp="col-sm-12"
                  @clicked-show-detail="clickedShowDetailModal"
                />
                {{item}} and {{productSelected}}
              </div>
            </span>
          </div>
        </div>

        <button class="btn btn-primary" @click="postUserDetails(mss)">Submit</button>
      </section>
    </div>
  </div>
</template>
<script>
import CheckBox from "../../../components/checkbox/Checkbox";
export default {
  name: "technology",
  data() {
    return {
      usageValue: "",
      value: "",
      campainCheckedNames: [],
      checked: "",
      productSelected: [],
      checkedValues: "",
      exists: null,
      inputValue: "",
      campaignMangment: [
        "Business to Customer (B2C)",
        "Business to Business (B2B)",
        "Customer to Customer (C2C)",
        "Customer to Business (C2B)",
        "E-Government",
        "M-Commerce",
      ],
    };
  },
  props: ["ms", "selected"],
  //method to show all the solutions that contains the user
  methods: {
    clickedShowDetailModal: function (campainCheckedNames) {
      console.log(campainCheckedNames);
      this.productSelected.push(campainCheckedNames);
    },
  },
  components: {
    CheckBox,
  },
};
</script>

This is CheckBox.vue

<template>
  <div class="row col-mb-0">
    <div
      :class="classProp + ' checkbox-margin'"
      v-for="singleSelector in groups"
      :key="singleSelector"
    >
      <div>
        <input
          :id="singleSelector+groupId"
          :value="singleSelector"
          class="checkbox-style"
          type="checkbox"
          v-model="checkedValues"
          @change="showDetailModal"
        />
        <label :for="singleSelector +groupId" class="checkbox-style-3-label">{{singleSelector}}</label>
      </div>
    </div>
  </div>
</template>
<script>
let groupId = 0;
export default {
  props: {
    groups: Array,
    name: String,
    classProp: String,
    value: String,
  },
  data() {
    return {
      groupId: groupId++,
      checkedValues: [],
      inputs: {},
    };
  },
  methods: {
    showDetailModal: function (e) {
      this.$set(this.inputs, this.value, e.target.value);
      this.$emit("clicked-show-detail", this.inputs);
    },
  },
};
</script>
<style scoped>
.checkbox-margin {
  margin-bottom: 10px;
}
</style>

Right Now, the line {{item}} and {{productSelected}} prints output like below as shown in screenshot enter image description here .

Problem: On every click/unclick of checkbox it adds an item to an array and not in the format I want. and if I select the checkbox on left only, it adds that item on right as well as shown in the screenshot above. It is due to the same array declaration, but I couldn't think more than that.

Expected Output: For every selected item, I want to print the list of selected checkboxes in an array format like below.

"selected_solutions": [{
        "name": "Adobe Campaign",
        "usage": [ "Business to Customer",...]
    }, {
        "name": "Marin Software",
        "usage": ["M-Commerce",...]
    }]

Even small hints or tips would be more than appreciated. I don't mind posting code on gist if required. Thank you.

Upvotes: 0

Views: 603

Answers (1)

ippi
ippi

Reputation: 10177

With checkbox-components you want to emit "event.target.checked" likeso:

this.$emit('input', event.target.checked)

That way it'll behave like a checkbox and you can use a v-model on the parent:

<CheckBox v-model="item.checked" ...>

I do not use v-model inside the component and instead just bind :checked="value", but that might be up to preference. But using both :value and v-model could (should?) cause problems because v-model is actually a :value + emitter under the hood (or so I heard).

Anyway, here is my minimal reusable checkbox-wrapper:

<template>
  <input type="checkbox" :checked="value" @change="handleChange" />
</template>

<script>
import Vue from 'vue'
export default Vue.extend({
  name: 'MyCheckbox',
  props: {
    value: { type: Boolean, default: false }
  },
  methods: {
    handleChange(event) {
      this.$emit('input', event.target.checked)
    }
  }
})
</script>

After that is done you can just filter on checked items:

computed: {
    checkedSolutions(){ 
        return this.ms[0].selected_solutions
            .filter( solution => solution.checked );
    }
}

Upvotes: 2

Related Questions