Search code examples
javascriptvue.jsvuejs2v-for

Using v-for with dynamic keys in Vuejs


I'm building a common table component in my Vuejs application something like this:

Table-Component:

<template>
    <div>
        <table class="table">
                <thead>
                <tr>
                    <th v-for="item in headers">
                        {{ item }}
                    </th>
                </tr>
                </thead>
                <tbody>
                <tr v-for="(item, index) in contents">
                    <th scope="row">
                        {{ index+1 }}
                    </th>
                    <td>
                        {{ item.first_name }}
                    </td>
                    <td>
                        {{ item.last_name }}
                    </td>
                    <td>
                        {{ item.username }}
                    </td>
                </tr>

                </tbody>
        </table>
    </div>
</template>

<script>
    export default {
        name: "table-type-1",
        props: ['contents', 'headers']
    }
</script>

This will work if I pass following data set in props, something like this:

data() {
    return {
        headers: ['#', 'First Name', 'Last Name', 'Username'],
        contents: [
            { first_name: 'Jhon', last_name: 'Stone', username: '@jhon' },
            { first_name: 'Lisa', last_name: 'Nilson', username: '@lisa' },
            { first_name: 'Larry', last_name: 'the Bird', username: '@twitter' }
        ]
    }
}

But since I'm building a common table so my data set can be different, it might be sometimes something like this:

data() {
    return {
        headers: ['#', 'Company Name', 'City', 'Turn Over (In Billions)'],
        contents: [
            { company_name: 'ABC Infotech', city: 'New Jersey', turn_over: 100 },
            { company_name: 'Amazon Web Services', city: 'New York', turn_over: 400 },
            { company_name: 'Digital Ocean', city: 'Washington', turn_over: 200 }
        ]
    }
}

Or may be a different structures. For this I'm thinking to pass a keys value set in my headers data which can determine which keys are represented to which column something like this:

data() {
    return {
        headers: [
            { title: '#', key: index, },
            { title: 'Company Name', key: 'company_name'},
            { title: 'City', key: 'city'},
            { title: 'Turn Over (In Billions)', key: 'turn_over' }
        ],
        contents: [
            { company_name: 'ABC Infotech', city: 'New Jersey', turn_over: 100 },
            { company_name: 'Amazon Web Services', city: 'New York', turn_over: 400 },
            { company_name: 'Digital Ocean', city: 'Washington', turn_over: 200 }
        ]
    }
}

Or simply pass the key variable:

data() {
    return {
        headers: ['#', 'Company Name', 'City', 'Turn Over (In Billions)'],
        keys: ['index', 'company_name', 'city', 'turn_over'],
        contents: [
            { company_name: 'ABC Infotech', city: 'New Jersey', turn_over: 100 },
            { company_name: 'Amazon Web Services', city: 'New York', turn_over: 400 },
            { company_name: 'Digital Ocean', city: 'Washington', turn_over: 200 }
        ]
    }
}

How can I achieve this?, or is it possible by this approach, where I can place these keys in my v-for element? Any suggestions are welcome. Thanks.


Solution

  • For each row loop through the headers, extract the key and get the content by key:

    new Vue({
      el: '#app',
      data: {
        headers: [
            { title: '#', key: 'index' },
            { title: 'Company Name', key: 'company_name'},
            { title: 'City', key: 'city'},
            { title: 'Turn Over (In Billions)', key: 'turn_over' }
        ],
        contents: [
            { company_name: 'ABC Infotech', city: 'New Jersey', turn_over: 100 },
            { company_name: 'Amazon Web Services', city: 'New York', turn_over: 400 },
            { company_name: 'Digital Ocean', city: 'Washington', turn_over: 200 }
        ]
      }
    })
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.min.js"></script>
    
    <div id='app'>
      <table class="table">
        <thead>
          <tr>
            <th v-for="item in headers">
              {{ item.title }}
            </th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(item, index) in contents">
            <th scope="row">
              {{ index+1 }}
            </th>
            <td v-for="{ key } in headers.slice(1)">
              {{ item[key] }}
            </td>
          </tr>
        </tbody>
      </table>
    </div>