I am new in Vue and still learning using it. I've been following example from this page: https://vue.ant.design/components/table/
I'm trying to fetch data using json to be displayed using Antd Tables.
But I include the js and css manually using and .
The data calling is fine as i can see from the console logged. But the table is not displaying any records.
I've been trying to code in here:
https://jsfiddle.net/dedychaidir/yvr5o8Lk/4/
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ant-design-vue#1.3.13/dist/antd.css" />
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/ant-design-vue#1.3.13/dist/antd.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-resource#1.5.1"></script>
<div id="app">
<template>
<a-table :columns="columns" :rowKey="record => record.login.uuid" :dataSource="data" :pagination="pagination" :loading="loading" #change="handleTableChange">
<template slot="name" slot-scope="name">
{{name.first}} {{name.last}}
</template>
</a-table>
</template>
</div>
And this is the script section:
const columns = [{
title: 'Name',
dataIndex: 'name',
sorter: true,
width: '20%',
scopedSlots: {
customRender: 'name'
},
}, {
title: 'Gender',
dataIndex: 'gender',
filters: [{
text: 'Male',
value: 'male'
},
{
text: 'Female',
value: 'female'
},
],
width: '20%',
}, {
title: 'Email',
dataIndex: 'email',
}];
var app = new Vue({
el: "#app",
mounted: function() {
this.fetch();
},
data: function() {
return {
data: [],
pagination: {},
loading: false,
columns,
}
},
methods: {
handleTableChange(pagination, filters, sorter) {
console.log(pagination);
const pager = {
...this.pagination
};
pager.current = pagination.current;
this.pagination = pager;
this.fetch({
results: pagination.pageSize,
page: pagination.current,
sortField: sorter.field,
sortOrder: sorter.order,
...filters,
});
},
fetch(params = {}) {
this.loading = true;
this.$http.get('https://randomuser.me/api',{params:{results:"10"}}).then(response => {
json = JSON.parse(response.bodyText);
const pagination = {
...this.pagination
};
pagination.total = 200;
this.loading = false;
this.data = json.results;
this.pagination = pagination;
console.log(this.data);
}, response => {
console.log(response.body);
});
},
},
});
Please show me if there are some error or mistakes.
Thank you.
I made codesandbox for you with provided code and everything works.
https://codesandbox.io/embed/vue-template-pluqh
Not sure, but maybe you just need to remove first <template> tag inside div#app because its not neccessary
Related
I have this component that shows a whole bunch of different components. Like so:
computed: {
...mapGetters('forms', ['formErrors']),
input: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
},
},
component() {
const components = {
'ls-text-field': () =>
import('../../../../common/ls-text-field.vue'),
'simple-date-picker': () =>
import('../../../../common/simple-date-picker.vue'),
select: 'v-select',
combobox: 'v-combobox',
};
return components[this.setting.component];
},
attributes() {
const attrs = {
'ls-text-field': {
label: this.setting.name,
},
'simple-date-picker': {},
select: {
label: 'Select this foo',
items: this.setting.options,
},
combobox: {
'return-object': true,
items: this.productList,
loading: this.loading_product_list,
'item-value': 'sku',
'item-text': 'sku',
label: this.setting.name,
name: this.setting.key,
},
};
return {
...attrs[this.setting.component],
'error-messages': this.formErrors(this.setting.key),
};
},
},
and the Template looks something like this:
<template>
<v-col md="4" cols="12">
<component
:is="component"
v-bind="attributes"
v-model="input"
:search-input.sync="searchSku"
/>
But you'll notice I had to do v-model in the template and not in the computed property. I suppose there is NO way to do this:
attributes() {
const attrs = {
'ls-text-field': {
label: this.setting.name,
},
'simple-date-picker': {},
select: {
label: 'Select this foo',
items: this.setting.options,
},
combobox: {
'return-object': true,
items: this.productList,
loading: this.loading_product_list,
'item-value': 'sku',
'item-text': 'sku',
label: this.setting.name,
name: this.setting.key,
'v-model': this.item.info.someKey // This doesn't seem possible
},
};
I'm trying to populate an ag-grid component with data coming from a Vuex getter. The only remarkable thing to mention is that this data coming from the getter is asynchronous. When I debug the grid component I can see that the data from the getter is there but the rowData property from the grid is still empty and I get this error in the console:
This warning:
runtime-core.esm-bundler.js:38 [Vue warn]: Unhandled error during execution of mounted hook
at <Anonymous class="ag-theme-alpine" id="myGrid" columnDefs= {value: Array(7)} ... >
at
at <DesignSystem onVnodeUnmounted=fn ref=Ref< Proxy {callWebsocket: ƒ, sendMessage: ƒ, …} > >
at
at
at <ConfigProvider theme-overrides= {common: {…}, Checkbox: {…}, Radio: {…}, Button: {…}, Switch: {…}} theme=null >
at
This Error:
Uncaught (in promise) TypeError: this.gridOptions.columnDefs.forEach is not a function
at GridOptionsWrapper2.checkColumnDefProperties (ag-grid-community.cjs.js:18300:37)
at GridOptionsWrapper2.init (ag-grid-community.cjs.js:18240:18)
at ag-grid-community.cjs.js:1113:76
at Array.forEach ()
at Context2.callLifeCycleMethodsOnBean (ag-grid-community.cjs.js:1113:24)
at ag-grid-community.cjs.js:1096:70
at Array.forEach ()
at Context2.callLifeCycleMethods (ag-grid-community.cjs.js:1096:23)
at Context2.wireBeans (ag-grid-community.cjs.js:975:14)
at new Context2 (ag-grid-community.cjs.js:953:14)
Here's my component template:
<template>
<div class="test-container">
<ag-grid-vue
class="ag-theme-alpine"
id="myGrid"
:columnDefs="columnDefs"
domLayout="autoHeight"
unSortIcon="true"
#grid-ready="onGridReady"
:animateRows="true"
:rowData="rowData"
:defaultColDef="defaultColDef"
>
</ag-grid-vue>
</div>
</template>
And here's my setup function (I'm using Vue's 3 Composition API):
import { AgGridVue } from "ag-grid-vue3";
import { useActions, useGetters } from "vuex-composition-helpers";
import { reactive, onMounted, ref } from "vue";
export default {
components: {
AgGridVue,
},
setup() {
const gridApi = ref(null);
const onGridReady = (params) => {
gridApi.value = params.api;
};
const rowData = reactive([]);
const columnDefs = reactive({
value: [
{ field: "brandId", sortable: true, checkboxSelection: true },
{ field: "category" },
{ field: "channel", headerName: "Brand" },
{ field: "channelReferenceId", headerName: "Requested" },
{ field: "id", headerName: "Updated" },
{ field: "status", headerName: "Subject" },
{ field: "subject", headerName: "Requester" },
],
});
const defaultColDef = {
sortable: true,
filter: true,
flex: 1,
};
const { fetchTickets } = useActions({
fetchTickets: "tickets/fetchTickets",
});
const { tickets } = useGetters({
tickets: "tickets/getRowData",
});
function getTickets() {
fetchTickets();
}
getTickets();
onMounted(() => {
rowData.value = tickets.value;
});
return {
onGridReady,
columnDefs,
rowData,
defaultColDef,
tickets,
getTickets,
};
},
As you can see I'm using the vuex-composition-helpers in order to fetch Tickets from an API and then use a getter that will be the main source of data to populate the ag-grid.
I finally came up with a solution for this, for some reason (that to be honest I still don't understand) you have to pass the ag-grid prop value to the component as "rowData.value" (I thought you don't need to specify it that way on the template). So this is the way to implement the component in the template:
<ag-grid-vue
:icons="icons"
class="ag-theme-alpine"
id="myGrid"
:columnDefs="columnDefs.value"
domLayout="autoHeight"
unSortIcon="true"
#grid-ready="onGridReady"
:animateRows="true"
:rowData="rowData.value"
>
And then this is the setup function using composition API:
<script>
import { AgGridVue } from "ag-grid-vue3";
import { useActions, useGetters } from "vuex-composition-helpers";
import { reactive, onMounted, onBeforeMount, ref } from "vue";
export default {
components: {
AgGridVue,
},
setup() {
const gridApi = ref(null);
const onGridReady = (params) => {
gridApi.value = params.api;
gridApi.value.sizeColumnsToFit();
};
const rowData = reactive([]);
const columnDefs = reactive({
value: [
{ field: "brandId", sortable: true, checkboxSelection: true },
{ field: "channel", sortable: true, suppressSizeToFit: true },
{ field: "channelReferenceId", sortable: true },
{ field: "createdOn", sortable: true, suppressSizeToFit: true },
{ field: "status", sortable: true, suppressSizeToFit: true },
{ field: "subject", sortable: true },
],
});
const defaultColDef = {
sortable: true,
filter: true,
flex: 1,
};
const { fetchTickets } = useActions({
fetchTickets: "tickets/fetchTickets",
});
const { tickets } = useGetters({
tickets: "tickets/getRowData",
});
function getTickets() {
fetchTickets();
}
getTickets();
const icons = ref(null);
const columnApi = ref(null);
onBeforeMount(() => {
icons.value = {
sortAscending: '<i class="fas fa-sort-alpha-down text-blue-400"></i>',
sortDescending: '<i class="fas fa-sort-alpha-up text-blue-400"></i>',
sortUnSort: '<i class="fas fa-sort text-blue-400"></i>',
};
});
onMounted(() => {
rowData.value = tickets;
});
return {
onGridReady,
columnDefs,
tickets,
getTickets,
rowData,
defaultColDef,
icons,
columnApi,
};
},
};
</script>
Important things to note:
declare rowData as an array (not an object like the ag-grid website does):
const rowData = reactive([]);
After setting up all the getters, etc and fetching the information:
onMounted(() => {
rowData.value = tickets;
});
I am using CoreUI React Smart Table, I cannot seem to figure out how to put the filter on certain columns only.
I want it to look like this:
Screenshot
The documentation is here, but it does not really seem to show how:
https://coreui.io/react/docs/components/smart-table/
Any help would be really appreciated.
Here is my code:
import React, { useState } from 'react'
import { CCardBody, CButton, CSmartTable } from '#coreui/react-pro'
import data from './_data.js'
const SmartTableDownloadableExample = () => {
const [currentItems, setCurrentItems] = useState(data)
const csvContent = currentItems.map((item) => Object.values(item).join(',')).join('\n')
const csvCode = 'data:text/csv;charset=utf-8,SEP=,%0A' + encodeURIComponent(csvContent)
return (
<CCardBody>
<CButton
color="primary"
className="mb-2"
href={csvCode}
download="coreui-table-data.csv"
target="_blank"
>
Download current items (.csv)
</CButton>
<CSmartTable
columnFilter={{ column: 'id' }}
columnSorter
items={data}
itemsPerPage={5}
onFilteredItemsChange={setCurrentItems}
pagination
/>
</CCardBody>
)
}
export default SmartTableDownloadableExample
I figured it out:
You need to add an columns object:
const columns = [
{
key: 'name',
_style: { width: '40%' },
_props: { color: 'primary', className: 'fw-semibold' },
},
'registered',
{ key: 'role', filter: false, sorter: false, _style: { width: '20%' } },
{ key: 'status', _style: { width: '20%' } },
{
key: 'show_details',
label: '',
_style: { width: '1%' },
filter: false,
sorter: false,
_props: { color: 'primary', className: 'fw-semibold' },
},
]
Then in the CSmartTable:
<CSmartTable
**columns={columns}**
columnFilter
columnSorter
items={data}
itemsPerPage={5}
onFilteredItemsChange={setCurrentItems}
pagination
/>
As per:
https://coreui.io/react/docs/components/smart-table/
I already parsing API using axios. After that I got the value then I adding to properties Data in Datatable but still not working. The value not parse to Datatable. When I console.log the data is showing. I am use API from https://jsonplaceholder.typicode.com/users.
And hear is my code:
import "./css/jquery.dataTables.css";
import React, { Component } from "react";
import axios from "axios";
const $ = require("jquery");
$.Datatable = require("datatables.net");
export default class Tbl extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
loading: true,
};
}
//option 1
async getUsersData() {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
console.log(res.data);
this.setState({ loading: false, users: res.data });
}
//option 2
async getUsersData1() {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
return res.data;
}
componentDidMount() {
//call option 1
this.getUsersData();
this.$el = $(this.el);
this.$el.DataTable({
data: this.state.users, //option 1
data: this.getUsersData1(), //option 2
columns: [
{ title: "Name", data: "name" },
{ title: "Username", data: "username" },
{ title: "Email", data: "email" },
{ title: "Phone", data: "phone" },
{ title: "Website", data: "website" }
],
});
}
componentWillMount() {}
render() {
return (
<table className="display" width="100%"
ref={(el) => (this.el = el)}>
</table>
);
}
}
I already try for option 1 and option 2 but still not working.
Thank,
The problem I can see here is that you initialize the plugin table in incorrect way. In order to include DataTable plugin, you should call as require('datatables.net')(window, $). Then after you have done loading data, you just simply call sync data to table again. Here is the snippet:
const $ = require("jquery");
require("datatables.net")(window, $);
// Keep as you have done
async getUsersData() {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
console.log(res.data);
this.setState({ loading: false, users: res.data });
}
// Init table data as component is mounted
componentDidMount() {
this.getUsersData().then(() => this.syncTable());
}
// Split as new function to init the datatable
syncTable() {
this.$el = $(this.el);
this.$el.DataTable({
data: this.state.users, //option 1
// data: this.getUsersData1(), //option 2
columns: [
{ title: "Name", data: "name" },
{ title: "Username", data: "username" },
{ title: "Email", data: "email" },
{ title: "Phone", data: "phone" },
{ title: "Website", data: "website" }
]
});
}
Here is the codesandbox for you: https://codesandbox.io/s/gallant-faraday-e25mk?file=/src/App.js
Use the "react-data-table-component" library. It is the best library for the data table.
Run this command to install it
npm install react-data-table-component styled-components
Then you have to import it in the react component page and use it
import DataTable from 'react-data-table-component';
const data = [{ id: 1, title: 'DataTable in ReactJS', year: '2021' } ...];
const columns = [
{
name: 'Name',
selector: 'name',
sortable: true,
},
{
name: 'Username',
selector: 'username',
sortable: true,
},
{
name: 'Email',
selector: 'email',
sortable: true,
},
{
name: 'Phone',
selector: 'phone',
sortable: true,
},
{
name: 'Website',
selector: 'website',
sortable: true,
},
];
class MyComponent extends Component {
render() {
return (
<datatable title="YourBlogCoach" columns="{columns}" data="{data}">
</datatable>
)
}
};
Check here for tutorial
When I create a WsapiDataStore, store.data.items and store.data.keys return empty arrays although I am able to see the keys and items when I do console.log(store.data)
store = Ext.create('Rally.data.WsapiDataStore', {
model: 'Defect',
context: {
project: '/project/xxxxxx'
},
autoLoad: true,
fetch: ['Rank', 'FormattedID', 'Name']
});
Output of console.log(store.data):
constructor {items: Array[0], map: Object, keys: Array[0], length: 0, allowFunctions: false…}
allowFunctions: false
events: Object
generation: 8
getKey: function (record) {
hasListeners: HasListeners
items: Array[7]
keys: Array[7]
length: 7
map: Object
sorters: constructor
__proto__: TemplateClass
Notice how the first line says "items: Array[0]" and "keys: Array[0]" but when expanded it says "items: Array[7]" and "keys: Array[7]". I'm also able to see the 7 records when I expand further.
Everything works as expected when I add a load listener and access the data from the listener function (but I don't want to do that)
I think the best way is to process the data via two Rally.data.WsapiDataStore's. You'll need to chain the listeners for the two stores together in order to properly handle the asynchronous loads. Here's an example that illustrates the process:
<!DOCTYPE html>
<html>
<head>
<title>MultipleModelExample</title>
<script type="text/javascript" src="https://rally1.rallydev.com/apps/2.0p5/sdk.js"></script>
<script type="text/javascript">
Rally.onReady(function() {
Ext.define('CustomApp', {
extend: 'Rally.app.App',
componentCls: 'app',
// Combined Story/Defect Records
dataRecords: null,
launch: function() {
//Write app code here
this.dataRecords = [];
Rally.data.ModelFactory.getModels({
types: ['HierarchicalRequirement','Defect'],
scope: this,
success: function(models) {
this.myModels = models;
this.storyStore = Ext.create('Rally.data.WsapiDataStore', {
model: models.HierarchicalRequirement,
fetch: true,
autoLoad: true,
remoteSort: true,
sorters: [
{ property: 'FormattedID', direction: 'Asc' }
],
listeners: {
load: this._processStories,
scope: this
}
});
}
});
},
_processStories: function(store, records, successful, opts) {
var storyRecords = [];
Ext.Array.each(records, function(record) {
//Perform custom actions with the data here
//Calculations, etc.
storyRecords.push({
FormattedID: record.get('FormattedID'),
Name: record.get('Name'),
Description: record.get('Description')
});
});
this.dataRecords = storyRecords;
this.defectStore = Ext.create('Rally.data.WsapiDataStore', {
model: this.myModels.Defect,
fetch: true,
autoLoad: true,
remoteSort: true,
sorters: [
{ property: 'FormattedID', direction: 'Asc' }
],
listeners: {
load: this._processDefects,
scope: this
}
});
},
_processDefects: function(store, records, successful, opts) {
var defectRecords = [];
Ext.Array.each(records, function(record) {
//Perform custom actions with the data here
//Calculations, etc.
defectRecords.push({
FormattedID: record.get('FormattedID'),
Name: record.get('Name'),
Description: record.get('Description')
});
});
var combinedRecords = defectRecords.concat(this.dataRecords);
this.add({
xtype: 'rallygrid',
store: Ext.create('Rally.data.custom.Store', {
data: combinedRecords,
pageSize: 25
}),
columnCfgs: [
{
text: 'FormattedID', dataIndex: 'FormattedID'
},
{
text: 'Name', dataIndex: 'Name', flex: 1
},
{
text: 'Description', dataIndex: 'Description', flex: 1
}
]
});
}
});
Rally.launchApp('CustomApp', {
name: 'MultipleModelExample'
});
});
</script>
<style type="text/css">
.app {
/* Add app styles here */
}
</style>
</head>
<body></body>
</html>