Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple select inputs in table header with unique models

Tags:

vue.js

I am receiving data from the backend that takes the following format

[ 
    [ 
        [ "123", "21/11/2013", "Data", "Data" ], 
        [ "234", "22/11/2013", "Data", "Data" ], 
        [ "345", "12/09/2018", "Data", "Data" ], 
    ], 
    [ 
        [ "123", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data" ], 
        [ "234", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data" ], 
        [ "345", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data" ] 
    ] 
]

Each fileData represents a table, so in the above example it should produce two tables. The data inside contains a tables rows, so each table above has two rows. In order to achieve this I am doing something like the following.

<table class="table" v-for="(file, index) in fileData" :key="index">
    <tbody>
        <tr v-for="(row, index2) in file":key="index2">
          <td v-for="(data, index3) in row" :key="index3">
            {{ data }}
          </td>
        </tr>
    </tbody>
</table>

This all seems to work fine. However, the data I am using does not have headers, but I need to prodive a header for each column that contains a select. As such I have added the following

<table class="table" v-for="(file, index) in fileData" :key="index">
    <thead>
        <tr>
           <th scope="col" v-for="(col, index2) in file[index]" :key="index2">
             <b-form-select v-model="options.value" :options="options"></b-form-select>
           </th>
        </tr>
    </thead>
</table>

Once again this seems to work. My problem is that I want the user to define what a column represents, using the select. At the moment, if I select something, they all change.

I have produced this Fiddle as an example https://jsfiddle.net/mhyv62bt/1/

How can I make the selects independent, and is it also possible to remove an option once selected?

Thanks

This seems to produce the correct number of header columns for each table.

Update I have a slightly different setup so trying to fit it in with my project. As such, I created the file THeadSelect.vue

<template id="theadselect">
  <thead>
  <tr>
    <th
      v-for="(i,index) in this.length_"
      :key="index"
    >
      <select
        v-model="headers[index]">
        <option disabled value="">
          Please select one
        </option>

        <option
          v-if="headers[index]"
          selected
        >
          {{headers[index]}}
        </option>
        <option
          v-for="option in filteredOptions"
          :key="option"
        >
          {{option}}
        </option>
      </select>
    </th>
  </tr>
  </thead>
</template>

<script>
export default {
  mounted () {
    this.$emit('update:headers',
      this.headers
        .concat(Array.from({ length: this.length_ }, _ => ''))
        .slice()
    )
  },
  props: {
    options: {
      type: Array,
      required: true
    },
    length: Number,
    headers: {
      type: Array,
      required: true
    }
  },
  computed: {
    length_: {
      get () {
        return this.length || this.options.length
      },
      set (l) {
        this.$emit('update:length', l)
      }
    },
    filteredOptions () {
      return this.options.filter(
        option => !this.headers.includes(option)
      )
    }
  }
}
</script>

I am then trying to use this within my page

<template>
  <div>
    <b-form
      novalidate
      @submit.stop.prevent=""
    >
      <div class="row">
        <div class="col-12">
          <table class="table table-bordered" v-for="(file, index) in fileData" :key="index">
            <thead
              is="THeadSelect"
              :options="['option1', 'option2', 'option3']"
              :headers.sync="headers"
            ></thead>
            <tbody>
            <tr v-for="(row, index2) in file" :key="index2">
              <td v-for="(data, index3) in row" :key="index3">
                {{ data }}
              </td>
            </tr>
            </tbody>
          </table>
        </div>
      </div>
    </b-form>
  </div>
</template>

<script>
import { THeadSelect } from '@/components/common/THeadSelect'

export default {
  components: {
    THeadSelect
  },
  computed: {
    fileData () {
      return this.$store.getters.fileData
    }
  },
  data () {
    return {
      headers: [],
      length: 10,
    }
  }
}
</script>

It is a bit messed up though. Only 3 selects are being displayed for each table. Additionally, if I select an option in table 1, it selects the same option in table 2. If you check out my original fiddle you can see the initial data I am trying to work with, so there will always be two tables.

like image 463
katie hudson Avatar asked Jun 11 '20 14:06

katie hudson


1 Answers

<div id='app'>
<table class="table table-bordered" v-for="(file, index) in fileData" :key="index">
    <thead>
  <tr>
    <th scope="col" v-for="(col, index2) in file[index]" :key="index2+index">
      <b-form-select v-model="selectedValue[index+index2]" :options="options">
        <template v-slot:first>
          <b-form-select-option :value="null" disabled>Ignore</b-form-select-option>
        </template>
      </b-form-select>
    </th>
  </tr>
</thead>
<tbody>
  <tr v-for="(row, index2) in file" :key="index2">
    <td v-for="(data, index3) in row" :key="index3">
      {{ data }}
    </td>
  </tr>
</tbody>

data: {
selectedValue: [],
mappedColumns: [],
selected: null,
options: [{
    value: '1',
    text: 'Option 1'
  },
  {
    value: '2',
    text: 'Option 2'
  },
  {
    value: '3',
    text: 'Option 3'
  }
],

You are using a single value in v-model for all the dropdowns. so, once you change a single dropdown. All of them gets changed.

Try the above solution, where I declared a new array in data which is selectedValue You can keep the data of which dropdown is selected in this array

like image 66
Sibashrit Pattnaik Avatar answered Oct 06 '22 22:10

Sibashrit Pattnaik