0
votes

I have a MyList.vue which gets directly imported by my app.vue. MyList.vue doesnt contain subcomponents, it only imports:

import store from "../store/store";
import { USER_FETCHLIST } from "../store/actions/user";

And the data looks like this:

export default {
  data () {
    return {
      tableData: [],
      tableheader: []
    }
  },
  created: function(){
    store.dispatch(USER_FETCHLIST).then((res) => {

        this.tableData = res["data"]["tableData"]
        this.tableHeader = res["data"]["tableHeader"]
    })
},
  methods: {
    changeRecord: function(element){
      console.log(element)
    }
  }

}

MyList.vue has the following markup for a bootstrap-vue modal:

<template v-for="(element, index) in tableData">
   <tr>
    //rest of the markup generating the columns carrying the data
      <td>
        <button v-on:click="changeRecord(element)" v-b-modal="`modal-${index}`">Aendern</button>

        <b-modal :id="'modal-' + index" title="BootstrapVue">
      <template v-for="(value, name) in element">

        <template v-if="typeof value==='object'">
          <template v-for="(nestedValue, nestedName) in value">
            <span>{{nestedName}}</span>
            <input type="text" :value="nestedValue" :class="'editFieldDivision-' + index">
          </template>
        </template>

          <template v-else>
            <span>{{name}}</span>
            <input type="text" :value="value" :class="'editFieldDivision-' + index">
          </template>
     </template>
    </b-modal>
  </td>
</tr>
</template>

The endresult when clicking the button is this dialog:

https://imgur.com/4aOEjde

The dialog might have more or less inputfields, depending on the data it receives from the backend.

However, this dialog is supposed to allow the user to apply changes to the respective record from the list in the background. Since I'm very new to vue, I don't know what the "vue-approach" to "grabbing" the user input would be. Should I use v-model? And if so, how do I do this, since the inserted data/observables are inserted dynamically. In the end, the data shall be put into a one-dimensional, where key-value has the "label" of the respective inputfield as key, and the value of the respective inputfield as value.

Furthermore, if the user discards the dialog, the changes inside the dialog shouldnt be applied to the datasets on the frontend.

1

1 Answers

1
votes

Here's one way to accomplish what you're looking for.

Keep a reference to the original object, and create a copy. You will then use the copy in your inputs inside the modal, this way you wont be modifying the original object. Then on the hide event, check if the OK button was pressed, if it was you copy all the values from the copy to the original object.

If cancel is clicked (or the modal is closed in another way), you simply clear the selected object and the copy.

This solution uses the lodash.set method, so you will need to include this in your project.

I also moved your modal out of your table loop. Since you can only edit one record at a time, you only really need one modal on your page.

new Vue({
  el: "#app",
  data() {
    return {
      data: [{
          Internal_key: "TESTKEY_1",
          extensiontable_itc: {
            description_itc: "EXTENSION_ITC_1_1",
            description_itc2: "EXTENSION_ITC_1_2",
          },
          extensiontable_sysops: {
            description_sysops: "EXTENSION_SYSOPS_1"
          }
        },
        {
          Internal_key: "TESTKEY_2",
          extensiontable_itc: {
            description_itc: "EXTENSION_ITC_2_1",
            description_itc2: "EXTENSION_ITC_2_2",
          },
          extensiontable_sysops: {
            description_sysops: "EXTENSION_SYSOPS_2_1"
          }
        }
      ],
      editingRecord: {
        original: null,
        copy: null
      }
    }
  },
  methods: {
    onEditModalHide(event) {
      if (event.trigger === "ok") {
        // if OK is pressed, map values back to original object.
        for(let fullKey in this.editingRecord.copy){
          const copyObject = this.editingRecord.copy[fullKey]
          /*
            this uses lodash set funcktion 
            https://www.npmjs.com/package/lodash.set
          */
          set(this.editingRecord.original, fullKey, copyObject.value)
        }
      }
      
      this.editingRecord.original = null
      this.editingRecord.copy = null;
    },
    changeRecord(record) {
      const flatCopy = this.flattenObject(record);
      this.editingRecord.original = record;
      this.editingRecord.copy = flatCopy;

      this.$nextTick(() => {
        this.$bvModal.show('edit-modal')
      })
    },
    flattenObject(ob) {
      var toReturn = {};

      for (var i in ob) {
        if (!ob.hasOwnProperty(i)) continue;

        if ((typeof ob[i]) == 'object' && ob[i] !== null) {
          var flatObject = this.flattenObject(ob[i]);
          for (var x in flatObject) {
            if (!flatObject.hasOwnProperty(x)) continue;
            console.log(x)
            toReturn[i + '.' + x] = {
              key: x,
              value: flatObject[x].value
            };
          }
        } else {
          toReturn[i] = {
              key: i,
              value: ob[i] 
          };
        }
      }
      return toReturn;
    }
  }
});
<link href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="//unpkg.com/[email protected]/dist/bootstrap-vue.min.css" rel="stylesheet" />

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/index.js"></script>

<div id="app" class="p-4">
  <table class="table table-bordered">
    <tr v-for="element in data">
      <template v-for="field in element">
        <template v-if="typeof field==='object'">
          <td v-for="nestedObjectValue in field">
            {{nestedObjectValue}}
          </td>
        </template>
      <template v-else>
          <td>
            {{field}}
          </td>
        </template>
      </template>
      <td>
        <button class="btn btn-primary" @click="changeRecord(element)">
          Edit
        </button>
      </td>
    </tr>
  </table>
  <b-modal id="edit-modal" v-if="editingRecord.copy" @hide="onEditModalHide">
    <template v-for="obj in editingRecord.copy">
      <label>{{ obj.key }}</label>
      <input v-model="obj.value"  class="form-control"/>
    </template>
  </b-modal>
</div>