Dynamically display table column/row with data that contains different size of nested array? - vue.js

I'm trying to display the data that I took from firestore and want to display it on a table using Vue.js and Element UI. I've tried looking for a solution but most shows for fixed amount of data whilst for my case I have an uneven number of data.
The structure of my data are as follows:
suppData: [{
comp_name: "company 1",
country: "country 1",
contInfo: [{
cpName: "John Doe",
phone: "123123",
email: "john#doe.com
},
prodList: [{
product: "eggs",
product: "shoes"
}
}],
comp_name: "company 2",
country: "country 2",
contInfo: [{
cpName: "Jack Doe",
phone: "1231231",
email: "jack#doe.com
},
{
cpName: "Michelle",
phone: "12412",
email: "mmichelle#doe.com
},
prodList: [{
product: "eggs",
}
}]
}]
The code I'm using for the table right now, played around with other methods such as formatter, flattening the data, but can't get it to work so help is appreciated!
<el-table-column label="Company Name" prop="company_name"></el-table-column>
<el-table-column label="Country" prop="country"></el-table-column>
<el-table-column label="Contacs" prop="contactName.cpName"></el-table-column>

For adding a row you just have to add an entry to your dataset. For columns you could create a seperate array with column data. You could manage this array yourself. This is an example how you could achieve it:
HTML:
<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column v-for="item in tableStructure" :key="item.prop" prop="item.prop" :label="item.label"></el-table-column>
</el-table>
<el-button #click="addRow">Add row</el-button>
<el-button #click="addColumn">Add column</el-button>
</template>
JS:
data() {
return {
tableStructure: [
{ label: "date", prop:"date" },
{ label: "name", prop:"name" }
],
tableData: [{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
}, {
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
}, {
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
}, {
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles'
}]
}
},
methods: {
addRow() {
this.tableData.push({
date: '2021-001-01',
name: 'New row',
address: 'Other address'
})
},
addColumn() {
this.tableStructure.push({ label: "address", prop:"address" })
}
}
}
Here is the example in codepen: https://codepen.io/reijnemans/pen/mdrOXgZ?editors=1011

Related

why the use of mobx caused the onChange of the table twice?

The first click on the page number will only trigger onChange once, and then click the page number will trigger twice.
codesandbox: https://codesandbox.io/s/late-shape-mznvvf?file=/demo.tsx
import "#arco-design/web-react/dist/css/arco.css";
import React from "react";
import { Table, TableColumnProps } from "#arco-design/web-react";
import { makeAutoObservable, runInAction } from "mobx";
import { observer } from "mobx-react";
class P {
pagination = {
current: 1,
pageSize: 2
};
constructor() {
makeAutoObservable(this, {
onChange: false
});
}
onChange(pagination) {
runInAction(() => {
this.pagination = pagination;
})
console.log("exec!");
}
}
const columns: TableColumnProps[] = [
{
title: "Name",
dataIndex: "name"
},
{
title: "Salary",
dataIndex: "salary"
},
{
title: "Address",
dataIndex: "address"
},
{
title: "Email",
dataIndex: "email"
}
];
const data = [
{
key: "1",
name: "Jane Doe",
salary: 23000,
address: "32 Park Road, London",
email: "jane.doe#example.com"
},
{
key: "2",
name: "Alisa Ross",
salary: 25000,
address: "35 Park Road, London",
email: "alisa.ross#example.com"
},
{
key: "3",
name: "Kevin Sandra",
salary: 22000,
address: "31 Park Road, London",
email: "kevin.sandra#example.com"
},
{
key: "4",
name: "Ed Hellen",
salary: 17000,
address: "42 Park Road, London",
email: "ed.hellen#example.com"
},
{
key: "5",
name: "William Smith",
salary: 27000,
address: "62 Park Road, London",
email: "william.smith#example.com"
},
{
key: "6",
name: "Jane Doe",
salary: 23000,
address: "32 Park Road, London",
email: "jane.doe#example.com"
},
{
key: "7",
name: "Alisa Ross",
salary: 25000,
address: "35 Park Road, London",
email: "alisa.ross#example.com"
},
{
key: "8",
name: "Kevin Sandra",
salary: 22000,
address: "31 Park Road, London",
email: "kevin.sandra#example.com"
},
{
key: "9",
name: "Ed Hellen",
salary: 17000,
address: "42 Park Road, London",
email: "ed.hellen#example.com"
},
{
key: "10",
name: "William Smith",
salary: 27000,
address: "62 Park Road, London",
email: "william.smith#example.com"
}
];
const application = new P();
const App = observer(() => {
return (
<Table
pagination={application.pagination}
columns={columns}
data={data}
onChange={(pagination) => application.onChange(pagination)}
/>
);
});
export default App;
why the use of mobx caused the onChange of the table twice?
know why the use of mobx caused the onChange of the table twice?

Display column with condition - Bootstrap-vue - VueJS [duplicate]

I'd like to only show one of my columns if the current user is an admin. I'm not sure how to do this with bootstrapVue. Any ideas?
Here's a snippet based on Troy's comment.
I've added a custom property to the field object called requiresAdmin. This is not part of standard Bootstrap-Vue.
You can use this to filter out all the fields that require's the user to be an admin in a computed property. Based on whether the user is an admin or not. This makes it easy to add and remove fields that require's the user to be an admin.
new Vue({
el: '#app',
computed: {
computedFields() {
// If the user isn't an admin, filter out fields that require auth.
if(!this.isUserAdmin)
return this.fields.filter(field => !field.requiresAdmin);
// If the user IS an admin, return all fields.
else
return this.fields;
}
},
data() {
return {
isUserAdmin: false,
fields: [
{ key: 'first', label: 'First Name' },
{ key: 'last', label: 'Last Name' },
{ key: 'age', label: 'Age' },
{ key: 'sex', label: 'Sex' },
{ key: 'secretActions', label: 'Secret Actions', requiresAdmin: true },
],
items: [
{ first: 'John', last: 'Doe', sex: 'Male', age: 42 },
{ first: 'Jane', last: 'Doe', sex: 'Female', age: 36 },
{ first: 'Rubin', last: 'Kincade', sex: 'Male', age: 73 },
{ first: 'Shirley', last: 'Partridge', sex: 'Female', age: 62 }
]
}
}
})
<link href="https://unpkg.com/bootstrap#4.4.1/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/bootstrap-vue#2.3.0/dist/bootstrap-vue.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.3.0/dist/bootstrap-vue.js"></script>
<div id="app" class="p-3">
<b-btn #click="isUserAdmin = !isUserAdmin">
Toggle admin user ({{ isUserAdmin }})
</b-btn>
<br /><br />
<b-table :fields="computedFields" :items="items">
<template v-slot:cell(secretActions)>
<b-btn>Edit User</b-btn>
<b-btn>Delete User</b-btn>
</template>
</b-table>
</div>

How to implement Groupping in Nativescript Vue RadDataForm?

Want to use Fields grouping Documention is not prvided event the topic of grouping nor the example. Most of the example are using typescript. Event the Google is not showing the result.
<RadDataForm
ref="dataform"
:source="customerForm"
:metadata="customerFormMetadata"
:groups="groups"
/>
customerFormMetadata: {
isReadOnly: false,
commitMode: "Immediate",
validationMode: "Immediate",
propertyAnnotations: [
{
name: "customer_name_1",
displayName: "Customer Name",
index: 0,
groupName: "Personal",
editor: "Text"
},
groups: [
Object.assign(new PropertyGroup(), {
name: "Personal",
collapsible: true,
collapsed: false
}),
Object.assign(new PropertyGroup(), {
name: "Address",
collapsible: true,
collapsed: true
})
],
Grouping doesn't require any addtional configuration while using with Vue, it's pretty straight forward as described in the core docs.
Example
<template>
<Page class="page">
<ActionBar title="Home" class="action-bar" />
<RadDataForm :source="person" :metadata="groupMetaData" />
</Page>
</template>
<script>
import Vue from "nativescript-vue";
import RadDataForm from "nativescript-ui-dataform/vue";
Vue.use(RadDataForm);
export default {
data() {
return {
person: {
name: "John",
age: 23,
email: "john#company.com",
city: "New York",
street: "5th Avenue",
streetNumber: 11
},
groupMetaData: {
propertyAnnotations: [{
name: "city",
index: 3,
groupName: "Address",
editor: "Picker",
valuesProvider: [
"New York",
"Washington",
"Los Angeles"
]
},
{
name: "street",
index: 4,
groupName: "Address"
},
{
name: "streetNumber",
index: 5,
editor: "Number",
groupName: "Address"
},
{
name: "age",
index: 1,
editor: "Number",
groupName: "Main Info"
},
{
name: "email",
index: 2,
editor: "Email",
groupName: "Main Info"
},
{
name: "name",
index: 0,
groupName: "Main Info"
}
]
}
};
}
};
</script>
Edit:
As discussed in the docs, to make the Group collapsible use the groupUpdate event.
onGroupUpdate: function(args) {
let nativeGroup = args.group;
if (args.ios) {
nativeGroup.collapsible = true;
} else {
nativeGroup.setExpandable(true);
}
}
Updated Playground

Hide column header in vue js md-table

I'm trying to hide table columns in vue material when the window gets smaller.
Like so:
<md-table-cell class="md-layout-item md-medium-hide" md-label="Job Title" md-sort-by="title">{{ item.title }}</md-table-cell>
But as you can see on this code sandbox
https://codesandbox.io/s/zz6v9j7vm4
The "job title" column stays even though the rows are gone.
How can I also make the row headers disappear?
Maybe it's not the best solution, but it work for me.
<template>
<div>
<md-table v-model="users" md-sort="name" md-sort-order="asc" md-card>
<md-table-toolbar> <h1 class="md-title">Users</h1> </md-table-toolbar>
<md-table-row slot="md-table-row" slot-scope="{ item }">
<md-table-cell md-label="ID" md-numeric>{{ item.id }}</md-table-cell>
<md-table-cell md-label="Name" md-sort-by="name">{{
item.name
}}</md-table-cell>
<md-table-cell md-label="Email" md-sort-by="email">{{
item.email
}}</md-table-cell>
<md-table-cell md-label="Gender" md-sort-by="gender">{{
item.gender
}}</md-table-cell>
<md-table-cell
class="md-layout-item"
v-if="isVisible"
md-label="Job Title"
md-sort-by="title"
>{{ item.title }}</md-table-cell
>
</md-table-row>
</md-table>
</div>
</template>
<script>
export default {
name: "TableSort",
data: () => ({
users: [
{
id: 1,
name: "Shawna Dubbin",
email: "sdubbin0#geocities.com",
gender: "Male",
title: "Assistant Media Planner"
},
{
id: 2,
name: "Odette Demageard",
email: "odemageard1#spotify.com",
gender: "Female",
title: "Account Coordinator"
},
{
id: 3,
name: "Lonnie Izkovitz",
email: "lizkovitz3#youtu.be",
gender: "Female",
title: "Operator"
},
{
id: 4,
name: "Thatcher Stave",
email: "tstave4#reference.com",
gender: "Male",
title: "Software Test Engineer III"
},
{
id: 5,
name: "Clarinda Marieton",
email: "cmarietonh#theatlantic.com",
gender: "Female",
title: "Paralegal"
}
],
windowWidth: null,
isVisible: true
}),
methods: {
handleWindowResize(event) {
this.windowWidth = event.currentTarget.innerWidth;
this.isVisible = this.windowWidth <= 720 ? false : true;
}
},
beforeDestroy: function() {
window.removeEventListener("resize", this.handleWindowResize);
},
mounted() {
window.addEventListener("resize", this.handleWindowResize);
}
};
</script>

Vue.js - search sort table with an image field

I have a Vue.js component/view that shows the data as follows:
<tbody v-for="item in items">
<tr>
<td width="15%"><img :src="item.image"></td>
<td width="50%">{{item.name}}</td>
<td>{{item.purchasedate | moment(" MMMM Do YYYY") }}</td>
<td>${{item.price}}</td>
<td>Item destination link</td>
</tr>
</tobdy>
The data is powered by a simple axios get call that returns the items array. I need to implement a search and sort function. I have tried several out of box components. Including out of box components available on NPM e.g. vue-good-table, vue-table-component, and grid-component. There are two issues I am facing with these
1. The image cannot be displayed and it only returns the URL
2. Date cannot be formatted - I am using moment.js for that.
I would like to sort by name, price, and purchasedate while displaying the image. Any suggestions?
with vue-good-table,you can set column option like this:
columns: [
{
label: 'photo',
field: 'photo',
html: true
},
{
label: 'Name',
field: 'name',
filterOptions: {
enabled: true,
},
},
{
label: 'Age',
field: 'age',
type: 'number',
},
{
label: 'Created On',
field: 'createdAt',
formatFn: v=>moment(v).format(" MMMM Do YYYY")
},
{
label: 'Percent',
field: 'score',
type: 'percentage',
},
],
and data like this:
rows: [
{ id:1,photo:"/static/logo.png", name:"John", age: 20, createdAt: '201-10-31:9: 35 am',score: 0.03343 },
{ id:2,photo:"/static/logo.png", name:"Jane", age: 24, createdAt: '2011-10-31', score: 0.03343 },
{ id:3,photo:"/static/logo.png", name:"Susan", age: 16, createdAt: '2011-10-30', score: 0.03343 },
{ id:4,photo:"/static/logo.png", name:"Chris", age: 55, createdAt: '2011-10-11', score: 0.03343 },
{ id:5,photo:"/static/logo.png", name:"Dan", age: 40, createdAt: '2011-10-21', score: 0.03343 },
{ id:6,photo:"/static/logo.png", name:"John", age: 20, createdAt: '2011-10-31', score: 0.03343 },
{ id:7,photo:"/static/logo.png", name:"Jane", age: 24, createdAt: '20111031' },
{ id:8,photo:"/static/logo.png", name:"Susan", age: 16, createdAt: '2013-10-31', score: 0.03343 },
].map(o=>({
...o,
photo:`<img width="80" height="80" src="${o.photo}"/>`
}))
and the result is: