how to build dynamic table with vue? - html-table

I tried to find the way build table from the following data property:
data(){
return {
headlist: [
{row: ID},
{row: Name},
{row: Title},
{row: Description },
{row: Actions }
],
}
Template code:
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Title</th>
<th>Description</th>
<th>Actions</th>
</tr>
Now tried to replace to :
<thead>
<tr v-repeat="headlist ">
<th>{{row}}</th>
</tr>
</thead>
Found example from https://012.vuejs.org/guide/list.html
What is wrong my code?

That's the documentation for the older version of VueJS. You shouldn't be referring to that. Also, you should be using the v-for directive:
<th v-for="(entry, i) in headlist" v-bind:key="i">
{{ entry.row }}
</th>
Proof-of-concept:
new Vue({
el: '#app',
data: function() {
return {
headlist: [{
row: 'ID'
},
{
row: 'Name'
},
{
row: 'Title'
},
{
row: 'Description'
},
{
row: 'Actions'
}
],
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table class="table table-bordered">
<thead>
<tr>
<th v-for="(entry, i) in headlist" v-bind:key="i">
{{ entry.row }}
</th>
</tr>
</thead>
</table>
</div>

Related

Vue.js making object.length value reactive

Trying to display Total records. Students.length works the first time on page load thanks to the created() method. However, calling filteredStudents(), is out of date. What is the easiest way to make this reactive?
<template>
<div class="d-inline-flex flex-row p-4 col-2">
Total record(s): {{ recordCount }}
</div>
<table class="table border table-striped table-hover">
<thead class="bg-secondary">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr v-for="student in filteredStudents()" :key="student._id">
<td>{{ student.firstName }}</td>
<td>{{ student.lastName }}</td>
<td>{{ student.email }}</td>
</tr>
</tbody>
</table>
</template>
<script>
import MixinCommon from '#/mixins/common.js'
export default {
data() {
return {
searchTerm: '',
Students: [],
studentcount: 0
}
},
created() {
this.Students = this.getSutdentList()
},
computed: {
recordCount() {
return this.Students.length
}
},
mixins: [MixinCommon],
methods: {
filteredStudents() {
return this.searchStudentList(this.searchTerm.toUpperCase(), this.Students)
},
}
}
</script>
I don't know the implementation of the searchStudentsList method, but you could try using the filteredStudents as a computed property, or making a watch property on the searchTerm in order to make the search again:
Using computed:
<template>
<div class="d-inline-flex flex-row p-4 col-2">
Total record(s): {{ recordCount }}
</div>
<table class="table border table-striped table-hover">
<thead class="bg-secondary">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr v-for="student in filteredStudents" :key="student._id">
<td>{{ student.firstName }}</td>
<td>{{ student.lastName }}</td>
<td>{{ student.email }}</td>
</tr>
</tbody>
</table>
</template>
<script>
import MixinCommon from '#/mixins/common.js'
export default {
data() {
return {
searchTerm: '',
Students: [],
studentcount: 0
}
},
created() {
this.Students = this.getSutdentList()
},
computed: {
recordCount() {
return this.Students.length
},
filteredStudents() {
return this.searchStudentList(this.searchTerm.toUpperCase(), this.Students)
},
},
mixins: [MixinCommon],
}
</script>
Using watch property:
<template>
<div class="d-inline-flex flex-row p-4 col-2">
Total record(s): {{ recordCount }}
</div>
<table class="table border table-striped table-hover">
<thead class="bg-secondary">
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Email</th>
</tr>
</thead>
<tbody>
<tr v-for="student in filteredStudents" :key="student._id">
<td>{{ student.firstName }}</td>
<td>{{ student.lastName }}</td>
<td>{{ student.email }}</td>
</tr>
</tbody>
</table>
</template>
<script>
import MixinCommon from '#/mixins/common.js'
export default {
data() {
return {
searchTerm: '',
Students: [],
filteredStudents: [],
studentcount: 0
}
},
created() {
this.Students = this.getSutdentList()
this.filteredStudents = this.searchStudentList(this.searchTerm.toUpperCase(), this.Students)
},
computed: {
recordCount() {
return this.Students.length
}
},
watch: {
searchTerm(newValue) {
this.filteredStudents = this.searchStudentList(newValue.toUpperCase(), this.Students)
}
}
mixins: [MixinCommon],
}
</script>

In vuejs, quoting variables in HTML element attribute doesn't work

Here is the code:
<tr v-for="(item, index) in detail" :key="item.name" class="[[ item.name ]]">
<td>[[ index + 1 ]]</td>
<td>[[ item.name ]]</td>
The rendered HTML looks like this:
<tr class="[[ item.name ]]">
<td>1</td>
<td>Job</td>
</tr>
<tr class="[[ item.name ]]">
<td>2</td>
<td>Jesse</td>
</tr>
<tr class="[[ item.name ]]">
<td>3</td>
<td>Wazert</td>
</tr>
The class="[[ item.name ]]" just don't change. What I expect is:
<tr class="Job">
<td>1</td>
<td>Job</td>
</tr>
<tr class="Jesse">
<td>2</td>
<td>Jesse</td>
</tr>
<tr class="Wazert">
<td>3</td>
<td>Wazert</td>
</tr>
How should I fix it?
First thing Square bracket not worked in vue.js you need to use interpolation for binding the data dynamically.
So you need to use like For Example
HTML
<table border="1">
<tr v-for="(item, index) in detail" :key="item.name" :class="item.name">
<td>{{ index + 1 }}</td>
<td>{{ item.name }}</td>
</tr>
</table>
JS
data: function () {
return {
detail: [{ name: "Job" }, { name: "Jesse" }, { name: "Wazert" }],
};
},
Here you can play with code
You need to use class-binding and interpolate the data:
new Vue({
el: "#app",
data: () => ({
detail: [ { name: "Job" }, { name: "Jesse" }, { name: "Wazert" } ]
})
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<table>
<tr v-for="(item, index) in detail" :key="item.name" :class="item.name">
<td>{{index + 1}}</td>
<td>{{item.name}}</td>
</tr>
</table>
</div>

set checkbox checked if value same vuejs

I'm displaying a list of menus in a table and looping with v-for, i want to set checkbox is checked if "id" from data menus same with "id_menu" from grupMenu, anyone has the same problem, please share it how i can solved, I'm realy new in Vue, thank's for helping,
new Vue({
el: "#app",
data: {
menus: [{
id: 1,
name_menu: "Setting",
parent: 0
},
{
id: 2,
name_menu: "Users",
parent: 1
},
{
id: 3,
name_menu: "Menu",
parent: 1
},
{
id: 4,
name_menu: "Role",
parent: 1
},
],
grupMenu: [{
id: 1,
id_user_group: 1,
id_menu: 1,
role: 1
},
{
id: 2,
id_user_group: 1,
id_menu: 2,
role: 0
},
]
},
methods: {
}
})
.text-center {
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<h2>Todos:</h2>
<table border="1">
<thead>
<tr>
<th rowspan="2" style="vertical-align:middle;text-align:center">Menu</th>
<th colspan="3" style="text-align:center">Previlege</th>
</tr>
<tr class="">
<th class="text-center">Insert</th>
</tr>
</thead>
<tbody>
<tr v-for="menu in menus" :key="menu.id">
<td v-if="menu.parent == 0" style="color:blue">
<input type="checkbox">
<!-- <input type="checkbox" v-model="checked"> -->
<b class="ml-2">{{menu.name_menu}}</b>
</td>
<td v-else>
<input type="checkbox" class="ml-5"> -- {{menu.name_menu}}
</td>
<td class="text-center">
<input type="checkbox">
</td>
<!-- </div> -->
</tr>
</tbody>
</table>
</div>
here in fiddle
If I understand correctly, you want the checkbox checked for each entry in menu whose id appears as a menu_id in grupMenu.
So write a method like this:
isInGrupMenu(id) {
return this.grupMenu.some((item) => item.id_menu === id);
}
and bind it to the checked attribute of each checkbox:
<input type="checkbox" :checked="isInGrupMenu(menu.id)">

Listing grouped data in table rows

I assume I have the following data
data() {
return {
users: [
{country: 'USA', name: 'Taylor'},
{country: 'UK', name: 'Tony'},
{country: 'USA', name: 'Mary'},
{country: 'JAPAN', name: 'Jane'},
{country: 'JAPAN', name: 'Moses'},
// More users from different countries in the world
]
}
}
I want to group by country and my final table structure to be like this, ordered by country name desc.
<table>
<tr>
<th>Country</th>
<th>User</th>
</tr>
<tr>
<td colspan="2">USA</td>
</tr>
<tr>
<td></td>
<td>Taylor</td>
</tr>
<tr>
<td></td>
<td>Mary</td>
</tr>
<tr>
<td colspan="2">UK</td>
</tr>
<tr>
<td></td>
<td>Tony</td>
</tr>
<tr>
<td colspan="2">JAPAN</td>
</tr>
<tr>
<td></td>
<td>Jane</td>
</tr>
<tr>
<td></td>
<td>Moses</td>
</tr>
</table>
How can I achieve this? I have tried playing with Lodash's groupBy but cant achieve it
let users = _.groupBy(this.users, function(user) { return user.country })
Here is one example of how to do it without any libraries.
console.clear()
new Vue({
el: "#app",
data:{
users: [
{country: 'USA', name: 'Taylor'},
{country: 'UK', name: 'Tony'},
{country: 'USA', name: 'Mary'},
{country: 'JAPAN', name: 'Jane'},
{country: 'JAPAN', name: 'Moses'},
// More users from different countries in the world
]
},
computed:{
byCountry(){
return this.users.reduce((acc, user) => {
(acc[user.country] = acc[user.country] || []).push(user.name)
return acc
}, {})
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div id="app">
<table>
<tr>
<th>Country</th>
<th>User</th>
</tr>
<template v-for="people, country in byCountry">
<tr>
<td colspan="2">{{country}}</td>
</tr>
<tr v-for="person in people">
<td></td>
<td>{{person}}</td>
</tr>
</template>
</table>
</div>

vueJS hide element in dynamic table row

I have a table that looks like this:
<table class="table">
<thead>
<tr>
<td><strong>Title</strong></td>
<td><strong>Job</strong></td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in rows">
<td><p class="title">My title</p></td>
<td><input type="text" v-model="row.job"></td>
<td><a #click="title()">Remove title</a></td>
</tr>
</tbody>
</table>
Now I wonder how I can toggle a jquery .hide() on the <p class="title">My title</p> when the remove title link is clicked on.
I dont want to use v-show since I am trying to understand how I can target elements within dynamic generated rows in vueJS.
The problem is that there are many rows in my table so every title tag must have a uniqe class and I dont understand how I can hide a specific title on dynamic generated rows
Can be done this way using v-show directive.
new Vue({
el: '.table',
data: {
rows: [
{ showTitle: true, job: 'A' },
{ showTitle: true, job: 'B' },
{ showTitle: true, job: 'C' }
]
}
});
<script src="https://unpkg.com/vue#2.5.2/dist/vue.min.js"></script>
<table class="table">
<thead>
<tr>
<td><strong>Title</strong></td>
<td><strong>Job</strong></td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in rows">
<td><p v-show='row.showTitle' class="title">My title</p></td>
<td><input type="text" v-model="row.job"></td>
<td><a #click="row.showTitle = false">Remove title</a></td>
</tr>
</tbody>
</table>
Edit:
Here is jQuery version but as I already said this is a bad practice.
new Vue({
el: '.table',
data: {
rows: [
{ job: 'A' },
{ job: 'B' },
{ job: 'C' }
]
},
methods: {
hideTitle(index) {
$(this.$refs['title' + index]).hide();
}
}
});
<script src="https://unpkg.com/vue#2.5.2/dist/vue.min.js"></script>
<script src="https://unpkg.com/jquery#3.2.1/dist/jquery.min.js"></script>
<table class="table">
<thead>
<tr>
<td><strong>Title</strong></td>
<td><strong>Job</strong></td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in rows">
<td><p class="title" :ref="'title' + index">My title</p></td>
<td><input type="text" v-model="row.job"></td>
<td><a #click="hideTitle(index)">Remove title</a></td>
</tr>
</tbody>
</table>
Try this one. it works. using v-f and title model
template
<table class="table">
<thead>
<tr>
<td><strong>Title</strong></td>
<td><strong>Job</strong></td>
<td></td>
</tr>
</thead>
<tbody>
<tr v-for="(row, index) in rows">
<td v-if="title === false"><p class="title">My title</p></td>
<td><input type="text" v-model="row.job"></td>
<td><a #click="title()">Remove title</a></td>
</tr>
</tbody>
</table>
script
data () {
title:false,
},
methods: {
title(){
this.title= true
}
}
As others have mentioned, mixing jQuery and Vue is not the best idea. However, if you must, you can use the event.target that #flypan mentioned along with some jQuery selectors to get what you want.
I put together a JSFiddle using your HTML as an example of what can be done:
new Vue({
el: '#app',
data: {
rows: [
{ job: 'A' }, { job: 'B' }
]
},
methods: {
title: function() {
$title = $(event.target).parent().parent().find("p");
$($title).hide();
}
}
});
You would probably want to tighten the selector to find the "p", but this is just an example. Here's the working JSFiddle:
https://jsfiddle.net/psteele/p5Lpxj5a/
For conditionally displaying, you can use v-show directive,document link here :
v-show doucment.
Hope this can be helpful to you!