vue.jsvuejs2frontendvue-componentv-model

Vue.js 2 components data property bound to the first or to one only instance of component


Need help. I'm fairly new to Vue.js and need some help and advice.

Context:
I have a component with BS modal inside which is rendered in a for loop and obviously has many instances.


Issue:
The very first rendered component has its data received from parent via props, and the rest component have their own (like row.id and etc.)


Question: How to fix it? Maybe the problem in BS modal?

Component:


    let vSelect = Vue.component("v-select", VueSelect.VueSelect);

    var scoringButton = Vue.component("scoring-button", {
      props: ["loadId", "causeData"],
      template: "#scoring-template",
      components: {
        "v-select": vSelect,
      },
      data: function () {
        return {
          scoredLoadId: this.loadId,
          scoring: null,
          causeId: null,
          selectedCause: null,
          causeList: this.causeData,
        };
      },
      computed: {
        showCauseList() {
          if (this.scoring === "1" || this.scoring === null) {
            return true;
          }
          return false;
        },
      },
    });

Template:


    <template v-cloak id="scoring-template">
      <div class="scoring-block" :id="scoredLoadId">
        <div class="scoring">
          <button
            v-if="scoring === '1'"
            title="Scoring button"
            type="button"
            class="btn btn-success scoring-btn"
            data-bs-toggle="modal"
            data-bs-target="#scoringModal"
          >
            <i class="bi bi-hand-thumbs-up-fill"></i>
          </button>
          <button
            v-else-if="scoring === '2'"
            title="Scoring button"
            type="button"
            class="btn btn-danger scoring-btn"
            data-bs-toggle="modal"
            data-bs-target="#scoringModal"
          >
            <i class="bi bi-hand-thumbs-down-fill"></i>
          </button>
          <button
            v-else
            title="Scoring button"
            type="button"
            class="btn btn-info scoring-btn"
            data-bs-toggle="modal"
            data-bs-target="#scoringModal"
          >
            <i class="bi bi-hand-thumbs-up-fill"></i>
            <i class="bi bi-hand-thumbs-down-fill"></i>
          </button>
        </div>
        <div
          class="modal fade scoring-modal"
          id="scoringModal"
          tabindex="-1"
          role="dialog"
          aria-hidden="true"
        >
          <div class="modal-dialog modal-dialog-centered">
            <div class="modal-content" :key="loadId">
              <div class="modal-header">
                <h1 class="modal-title">Load Scoring</h1>
                <button
                  type="button"
                  class="btn-close"
                  aria-label="Close"
                  data-bs-dismiss="modal"
                ></button>
              </div>

              <div class="modal-body">
                <div class="scoring-content">
                  <input
                    type="radio"
                    class="btn-check"
                    name="btnScore"
                    id="btnLike"
                    autocomplete="off"
                    checked="scoring === '1'"
                    value="1"
                    v-model="scoring"
                  />
                  <label
                    class="btn btn-outline-success"
                    for="btnLike"
                    @click="clearSelectedCause"
                  >
                    <i class="bi bi-hand-thumbs-up-fill"></i> Like
                  </label>
                  <input
                    type="radio"
                    class="btn-check"
                    name="btnScore"
                    id="btnDislike"
                    autocomplete="off"
                    :checked="scoring === '2'"
                    value="2"
                    v-model="scoring"
                  />
                  <label class="btn btn-outline-danger" for="btnDislike">
                    <i class="bi bi-hand-thumbs-down-fill"></i> Dislike
                  </label>
                </div>
                <div class="scoring-cause">
                  <v-select
                    :disabled="showCauseList"
                    label="name"
                    :options="causeList"
                    v-model="selectedCause"
                    placeholder="Choose a cause option"
                  ></v-select>
                </div>
              </div>
              <div class="modal-footer">
                <button
                  type="button"
                  class="btn btn-secondary"
                  data-bs-dismiss="modal"
                >
                  Close
                </button>
                <button type="button" class="btn btn-primary">
                  Save changes
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </template>

Parent:


        var mainTableApp = new Vue({
        el: "#main-table",
        data: {
            tableData: [],
            scoringCauseList: [
                 {
                   "id": 6,
                   "scoring_type": 0,
                   "name": "Late at loading",
                   "mark": "late_at_loading"
                 },
                 {
                   "id": 7,
                   "scoring_type": 0,
                   "name": "Special conditions were not respected",
                   "mark": "special_conditions_were_not_respected"
                 },
                 {
                   "id": 8,
                   "scoring_type": 0,
                    "name": "Bad/not enough information",
                   "mark": "bad_not_enough_information"
                  }
              ],
        },
        components:{
            'scoring-button': scoringButton,
        }
    });

Component in the main app block:


    <div 
   v-for="row in tableData"
   class="row-container"
   >
   ....
   <scoring-button 
      :id="row.LOAD_ID"
      :key="row.LOAD_ID"
      :load-id="row.LOAD_ID" 
      :cause-data="scoringCauseList"
   >
   </scoring-button>
   ....
</div>

I tried to resetting BS modal's data, but it didn't work. So, I went back to look for a solution in Vue part.

I know I may construct the whole thing not enough in a very right way, but this code below is the last version after many other solutions, have been tried with v-model, $emit, props etc.


Solution

  • Update: found solution.

    Added ":id" for all "input" fields I had in my component.

    So, to have reusable components their own data properties you need to have dynamic ":id" properties. So, that each data flows into their own component.

    
        <input
            type="radio"
            class="btn-check"
            name="btnScore"
            id="btnLike"    // <-- old line
            :id="`btnLike-${dynamicStr}`" // <-- new modified line
            autocomplete="off"
            checked="scoring === '1'"
            value="1"
            v-model="scoring"
          />
          <label
            class="btn btn-outline-success"
            for="btnLike" // <-- old line
           :for="'btnLike-${dynamicStr}'" // <-- new modified line
            @click="clearSelectedCause"
          >
       <i class="bi bi-hand-thumbs-up-fill"></i> Like
       </label>