0

I'm working on a project where I created a table component which is used on multiple pages with different configuration. Every table has it's configuration in a separate file where I store keys, titles and size classes for each column.

Data for each table body come from REST calls and they are loaded dynamically, paginated and then displayed.

<template slot="thead">
    <tr>          
        <th v-for="item in headers" :key="item.id" :class="item.classes">{{item.title}}</th>        
    </tr>      
</template>      
<template slot="tbody">        
    <tr v-for="skill in paginatedSkills" 
        :key="skill.id" 
        v-on:click="selectRow(skill)" 
        v-bind:class="{selectedRow: selectedSkill === skill}"
    >          
        <td class="cell-l">{{skill.name}}</td>          
        <td class="cell-m">{{skill.owner}}</td>          
        <td class="cell-s">{{skill.complexity}}</td>          
        <td class="cell-full">{{skill.description}}</td>        
    </tr>      
</template>

What I want to do is to avoid writing size class for every single cell in the tbody loop. I was hoping to get index of looped object and use it to retrieve the class from config object which is used to populate cells in thead.

<tr v-for="(skill, index) in paginatedSkills" ...>
        <td class="{headers[index].classes}">{{skill.name}}</td>

Using index on headers will return the correct item but as a string so obviously classes are not accessible. Any idea how to tweak it?

This options are no go, failing on compile

<td :class="{JSON.parse(headers[index]).classes}">{{skill.name}}</td>
<td :class="{JSON.parse(headers)[index].classes}">{{skill.name}}</td>
<td :class="{{JSON.parse(headers[index]).classes}}">{{skill.name}}</td>

1 Answer 1

2

To set class from a variable/property you have two options:

<td v-bind:class="headers[index].classes">{{skill.name}}</td>
<td :class="headers[index].classes">{{skill.name}}</td>

No need for curly braces here since v-bind already expects JS expression.

Update:

What you can also do, is to associate keys of skill object (name, owner, complexity, description) with their header, so each item of headers array will also have for example key property used to access value from skill object:

headers: [
    { id: 1, classes: 'cell-l', title: 'title', key: 'name' },
    { id: 2, classes: 'cell-s', title: 'title', key: 'owner' },
    ...
]

Thus, your code can be simplified the following way:

<tr v-for="skill in paginatedSkills" ...>          
    <td v-for="header in headers" v-bind:class="header.classes">{{skill[header.key]}}</td>
</tr>
Sign up to request clarification or add additional context in comments.

5 Comments

It's not working, I'm getting Vue warn: Error in render: "TypeError: Cannot read property 'classes' of undefined"
@dallows I just noticed, you probably have 4 elements in headers but trying to access it using index from paginatedSkills which is of different length and contain different data. You probably need to hardcode indexes like that: <td v-bind:class="headers[0].classes">{{skill.name}}</td>
That brings me back to hard-coding only this time it's less obvious what's happening, compared to using exact class name
@dallows Maybe less obvious but still keeps your class names at the single place. Anyway, see update to the answer
after update it works and it's even better solution than what I had before

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.