Vuetify dynamic data-table component - vue-component

I'm quite new to Vue development and I made a dynamic list component, using Vuetify v-data-table. In this component I receive a config object as a prop and get the configuration of the headers, links for redirections and some other stuff aswell.
Now I'm stuck with a problem: I can't format my cell's content because I can't use the normal v-slot:item.<property> approach to apply the filter. Is there any way of receiving a pointer of the filter and applying it to every value at the specified column?
Thanks.
edit:
Component =>
<template>
<div class="container">
<v-app>
<v-data-table :headers="config.cabecalho" :items="data" sort-by="id" class="elevation-1">
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>{{ config.titulo }}</v-toolbar-title>
<v-divider class="mx-4" inset vertical></v-divider>
<div class="flex-grow-1"></div>
<v-dialog v-model="dialog" max-width="500px">
<template v-slot:activator="{ on }">
<v-btn color="primary" dark class="mb-2" #click="novoItem">Novo</v-btn>
</template>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item.acoes="{ item }">
<v-icon small class="mr-2" #click="editItem(item)">edit</v-icon>
<v-icon small #click="deleteItem(item)">delete</v-icon>
</template>
</v-data-table>
</v-app>
</div>
</template>
<script>
import { mapState } from 'vuex'
import axios from 'axios'
export default {
data: () => ({
dialog: false,
data: []
}),
props: {
config:{
type: Object
}
},
methods:{
editItem(item) {
return this.$router.push(this.config.linkEdit + item.id)
},
deleteItem(item) {
const index = this.data.indexOf(item)
confirm("Tem certeza que quer excluir o item?") &&
axios.get(this.config.linkDelete)
.then(res => {
if (res.status == '200') {
alert('Item excluído com sucesso.')
}
else {
alert('Falha ao excluir item, tente novamente.')
}
})
.catch( e => console.log(e))
},
novoItem () {
this.$router.push(this.config.linkNovo)
}
},
async mounted() {
await setTimeout(() => {
this.data = [
{ id: 1, numero: '1', entidade:'Cliente Um', dtIni: '2019-06-01', dtFim: '2020-06-02', vlrTotal: 3500.00, diaVenc: '5' },
{ id: 2, numero: '2', entidade:'Cliente Dois', dtIni: '2019-07-01', dtFim: '2020-07-02', vlrTotal: 7000.00, diaVenc: '15' },
{ id: 3, numero: '3', entidade:'Cliente Três', dtIni: '2019-08-01', dtFim: '2020-08-02', vlrTotal: 1200.00, diaVenc: '10' },
{ id: 4, numero: '4', entidade:'Cliente Quatro', dtIni: '2019-09-01', dtFim: '2020-09-02', vlrTotal: 800.00, diaVenc: '25' },
{ id: 5, numero: '5', entidade:'Cliente Cinco', dtIni: '2019-09-10', dtFim: '2020-09-11', vlrTotal: 25000.00, diaVenc: '5' }
]
}, 100)
},
}
</script>
Page that calls the component passing config prop =>
template>
<div class="container">
<lista-base :config="this.config"></lista-base>
</div>
</template>
<script>
import ListaBase from '~/components/padrao/ListaBase.vue'
export default {
data(){
return {
config: {
linkBusca: '',
linkNovo: '/contrato/create',
linkEdit: '',
linkDelete: '',
titulo: 'Cadastro de Contratos',
cabecalho: [
{
text: "#",
align: "right",
value: "id"
},
{
text: "Entidade",
value: "entidade",
align: "left"
},
{
text: "Início",
value: "dtIni",
align: "center"
},
{
text: "Fim",
value: "dtFim",
align: "center"
},
{
text: "Valor Total (R$)",
value: "vlrTotal",
align: "right",
filtro: "formataNumero"
},
{
text: "Ações",
value: "acoes",
sortable: false,
align: "center"
}
],
}
}
},
components: {
ListaBase
},
}
</script>
I used dummy data object because it's an experimental project still.

Related

How can I update a Block Templates with dynamic data in WordPress Custom Blocks?

In the following code, I am trying to dynamically update a template with attribute data that is not available until the first useEffect call. In the code below, the first render of course has emoty attributes and displays defaults. I can trace the code and see the template get updated, but after the useInnerBlocksProps is called with the revised template, the data is still not rendered. what am I missing?
export default function Edit(props) {
const { PanelBody, PanelRow } = wp.components;
const { attributes, setAttributes } = props;
useEffect(() => {
setAttributes({'name': 'Edward Alan Thompson'});
setAttributes({'birth_date': '1 jan 1900'});
setAttributes({'death_date': '31 Dec 1990'});
setAttributes({'imageUrl': 'http://wordpressdevel.local/wp-content/uploads/2022/07/1.png'});
}, []);
const blockProps = useBlockProps( {
style:{minHeight: 40, width: '100%', border: "1px dotted red"}
});
const innerBlocksProps = useInnerBlocksProps(
{orientation: "horizontal"},
{template: [
[ 'core/columns', { columns: 2 }, [
[ 'core/column', {width: "20%"}, [
[ 'core/image', { url: attributes.imageUrl??''} ]
] ],
[ 'core/column', {}, [
[ 'core/heading', { content: attributes.name??''} ],
[ 'core/paragraph', { content: 'b. ' + attributes.birth_date??''} ],
[ 'core/paragraph', { content: 'd. ' + attributes.death_date??''} ]
] ],
]
]
]}
);
return (
<div >
<InspectorControls>
<PanelBody title="General" initialOpen={true}>
<PanelRow>
</PanelRow>
</PanelBody>
</InspectorControls>
<div {...blockProps}>
<div {...innerBlocksProps}></div></div>
</div>
);
}
I verified that the last render call does have the proper template definition, its just not what is displayed on the screen.
Looking at your code, the issue seems to be with how useInnerBlocksProps() is called: the first parameter expects blockProps followed by the innerBlocks content, eg:
edit.js
import { useEffect } from '#wordpress/element';
import { useInnerBlocksProps, useBlockProps } from '#wordpress/block-editor';
export default function Edit({ attributes, setAttributes }) {
// Nb. Removed code not related to issue for clarity
useEffect(() => {
// Call setAttributes once
setAttributes({
name: "Edward Alan Thompson",
birth_date: "1 jan 1900",
death_date: "31 Dec 1990",
image_url: "http://wordpressdevel.local/wp-content/uploads/2022/07/1.png",
});
}, []);
const blockProps = useBlockProps({
style: { minHeight: 40, width: '100%', border: "1px dotted red" }
});
const TEMPLATE = [
['core/columns', {}, [ // Number of columns not needed
['core/column', { width: '20%' }, [
['core/image', { url: attributes.image_url ?? '' }]],
],
['core/column', {}, [
['core/heading', { content: attributes.name ?? '' }],
['core/paragraph', { content: 'b. ' + attributes.birth_date ?? '' }],
['core/paragraph', { content: 'd. ' + attributes.death_date ?? '' }]
]]
]]]
const { children, ...innerBlocksProps } = useInnerBlocksProps(blockProps,
{
orientation: "horizontal",
template: TEMPLATE
}
);
return (
<div {...innerBlocksProps}>
{children}
</div>
);
}
Ref: Inner Blocks: Using a react hook
I came to this conclusion after testing your template definition by itself using <InnerBlocks .../> then checked what useInnerBlocksProps() expected.

In Sanity/Nextjs, how do I make a page of categories that can open a new page with the selected categories subcategories?

I'm using nextjs for my frontend, and sanity for my backend. I have a page that shows a list of categories (e.g., sketches, paintings, exhibitions) and each have their own subcategories (e.g., exhibitions -> place a, place b, place c; sketches -> set a, set b, set c, set d). When you select one of those subcategories (e.g., place b), it will open a page with everything in that chosen subcategory.
I want to make it so that if the user clicks a category on one webpage, it will open a new webpage with its specific subcategories (children?).
Here are my schemas for the categories ('category') and subcategories ('set'):
// category.js
export default {
name: 'category',
type: 'document',
title: 'Category',
fields: [
{
name: 'category_name',
type: 'string',
title: 'Category Name'
},
{
name: 'category_image',
type: 'image',
title: 'Category Image'
},
{
name: 'categoryImage_alt',
title: 'Alt',
type: 'string'
},
{
name: 'contained_sets',
type: 'array',
title: 'Contained Sets',
of: [{
type: 'reference',
to: [{type: 'set'}]
}]
}
]
}
// setsSchema.js
export default {
name: 'set',
type: 'document',
title: 'Set',
fields: [
{
name: 'set_name',
type: 'string',
title: 'Set Name',
},
{
name: 'set_images',
type: 'array',
title: 'Set Images',
of: [
{
name: 'image',
type: 'image',
title: 'Image',
options: {
hotspot: true,
},
fields: [
{
name: 'alt',
type: 'string',
title: 'Alternative Text',
options: {
isHighlighted: true
}
},
{
name: 'name',
type: 'string',
title: 'Name',
options: {
isHighlighted: true
}
},
{
name: 'date',
type: 'string',
title: 'Date',
options: {
isHighlighted: true
}
},
{
name: 'size',
type: 'string',
title: 'Size',
options: {
isHighlighted: true
}
},
{
name: 'materials',
type: 'string',
title: 'Materials',
options: {
isHighlighted: true
}
},
]
},
]
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'set_name'
}
}
]
}
This is my webpage with the categories:
import React, { useState, useEffect } from 'react';
import { client, urlFor } from '../lib/client';
import { Header, Footer } from '../components';
import Link from 'next/link';
const gallery = () => {
// fetches sanity data
const [categoryData, setCategories] = useState(null);
useEffect(() => {
client.fetch(
`*[_type=="category"]{
categoryImage_alt,
category_image{
asset->{
_id,
url
}
},
category_name,
contained_sets
}`)
.then((data) => setCategories(data))
.catch(err => console.error(err));
}, [] );
return (
<div>
<Header />
<main className="main-gallery">
<div className="title">
<div className="title-line-left"></div>
<h2>categories</h2>
<div className="title-line-right"></div>
</div>
<div className="categories">
<ul className="categories-container">
{categoryData && categoryData.map((category, index) => (
<li>
<Link href="/sets"><img src={urlFor(category.category_image).auto('format').url()} alt={category.categoryImage_alt}/></Link>
</li>
))}
</ul>
</div>
</main>
<Footer />
</div>
)
}
export default gallery
This page is for sets, which currently shows all of the sets/subcategories, and not just the selected categories subcategories. I've tried a couple things but nothing has worked.
import React, { useState, useEffect } from 'react';
import { client, urlFor } from '../lib/client';
import { Header, Footer } from '../components';
const sets = () => {
// fetches sanity data
const [galleryData, setGalleryData] = useState(null);
useEffect(() => {
client.fetch(
`*[_type=="set"]{
set_name,
slug,
set_images,
image{
asset->{
_id,
url
}
},
}`)
.then((data) => setGalleryData(data))
.catch(err => console.error(err));
}, [] );
return (
<div>
<Header />
<main className="main-gallery">
<div className="title">
<div className="title-line-left"></div>
<h2></h2>
<div className="title-line-right"></div>
</div>
<div className="categories">
<ul className="categories-container">
{galleryData && galleryData.map((set, index) => (
<li>
<img src={urlFor(set.set_images[0]).auto('format').url()} alt={set.set_name}/>
</li>
))}
</ul>
</div>
</main>
<Footer />
</div>
)
}
export default sets

how can I make the data no longer pass in the adjacent column when there is no space in react table bootstrap?

I would like when there is no space to lower the letters that do not fit with a lower level.Can i resolve this using css ?
I tried in various ways I read the documentation but nothing worked just changing the color :(
I really need to know if there is a solution as soon as possible, thanks in advance :)
There is my table when there is no space
There is my code
import "react-bootstrap-table-next/dist/react-bootstrap-table2.min.css";
import "bootstrap/dist/css/bootstrap.min.css";
import BootstrapTable from "react-bootstrap-table-next";
import paginationFactory from "react-bootstrap-table2-paginator";
import Sidebar from "./sidebar/Sidebar";
import 'bootstrap/dist/css/bootstrap.css';
import React, { useEffect, useState } from "react";
import axiosInstance from "./axios";
import cellEditFactory from 'react-bootstrap-table2-editor';
import { Button } from "react-bootstrap";*
const UsersList = () => {
const [users,setUsers] = useState([]);
useEffect( () => {
axiosInstance.get("users")
.then(res => {
const val = res.data;
setUsers( val);
})
.catch(error => {
console.log(error);
});
}, []);
let isFollow = true;
const onFollowChanged =() => {
isFollow = !isFollow;
console.log(isFollow);
}
const linkFollow = (cell, row, rowIndex, formatExtraData) => {
return (
<Button
onClick={() => {
onFollowChanged();
}}
>
Follow
</Button>
);
};
onFollowChanged.bind();
const columns = [
{
dataField: 'index',
text: 'ID',
formatter: (cell, row, rowIndex, formatExtraData) => {
return rowIndex + 1;
},
sort: true,
},
{
dataField: "username",
text: "Username",
},
{
dataField: "email",
text: "Email",
},
{
dataField: "fullName",
text: "Full Name"
},
{
dataField: "address",
text: "Address"
},
{
dataField: "status",
text: "Status"
},
{
dataField: "follow",
text: "EDIT",
editable: false,
formatter: linkFollow
}
];
const rowEvents = {
onClick: (e, row, rowIndex) => {
window.location.assign("/home");
}
};
return (
<div>
<Sidebar />
<div className="container" style={{ padding: "20px" }}>
<BootstrapTable
striped hover condensed
trClassName='tr-string-example'
keyField="id"
data={users}
columns={columns}
pagination={paginationFactory({ sizePerPage: 5 })}
cellEdit={ cellEditFactory({ mode: 'click' }) }
/>
</div>
</div>
);
}
export default UsersList;

Vue.js - Invalid prop: type check failed for prop "src". Expected String, Object, got Promise

I'm trying to get an image inserted into my firebase's firestore and storage and display it on a v-card
my v-card code:
<v-row>
<v-col cols="3" v-for="massage in massages" :key="massage.id">
<v-card
class="mx-auto"
max-width="400"
>
<v-img
v-if="massage.image"
class="white--text align-end"
height="200px"
:src="massage.image"
>
</v-img>
<v-card-title>{{massage.title}}</v-card-title>
<v-card-text class="text--primary">
<div>{{massage.shortDescription}}</div>
</v-card-text>
<v-card-actions>
<v-btn
color="orange"
text
#click="goTodetail(massage.id)"
>
Explore
</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
my script:
<script>
import{ db, storage} from '#/firebase.js';
export default {
el: '#vue',
name: 'BaseHeading',
// massId:this.$route.params.Pid,
components: {
BaseInfoCard: () => import('#/components/base/InfoCard'),
},
data() {
return{
massages:[],
showmassage: false,
showrehabilitation: false,
showsupport: false,
modal_1: true,
modal_2: false,
modal_3: false,
}
},
created() {
try{
db.collection("massages").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
let img = ''
if(doc.data().image){
img = storage.ref().child(doc.data().image).getDownloadURL()
}
this.massages.push({
id: doc.id,
title: doc.data().title,
shortDescription: doc.data().shortDescription,
image: img
})
})
});
}catch(e){
console.log(e)
}
},
}
</script>
I think it provides promise but cannot figure out how to deal with it. The error is Invalid prop: type check failed for prop "src". Expected String, Object, got Promise.
I tried to put the following in the props:
props: {
src: [ String, Object],
},
but I still have the same error
Resolve the Promise when retrieving the image URL, before you pass it into your massage object.
created() {
try {
db.collection('massages')
.get()
.then((querySnapshot) => {
querySnapshot.forEach(async (doc) => {
// start pertinent change
if (doc.data().image) {
storage
.ref()
.child(doc.data().image)
.getDownloadURL()
.then((url) => {
this.massages.push({
id: doc.id,
title: doc.data().title,
shortDescription: doc.data().shortDescription,
image: url,
})
})
} else {
this.massages.push({
id: doc.id,
title: doc.data().title,
shortDescription: doc.data().shortDescription,
})
}
// end pertinent change
})
})
} catch (e) {
console.log(e)
}
}

Data not showing on Firebase, Using V-data-table Vue.js

The data is not showing, I do not know how to push the value from the firebase to the v-data-table values. Here is my code.
<template>
<div class="dashboard">
<h2 class="subheading mx-5">Subject</h2>
<v-btn block color="primary mt-5" #click="enrollSubjects()">Enroll Subjects</v-btn>
<v-container class="my-5">
<template>
<v-card>
<v-card-title>
Courses
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="search" label="Search" single-line hide-details></v-text-field>
</v-card-title>
<v-data-table v-model="selected" :headers="headers" :items="courses" show-select :single-select="singleSelect" item-key="descrip_title" :search="search">
</v-data-table>
</v-card>
</template>
</v-container>
</div>
</template>
<script>
// # is an alias to /src
import db from '#/firebase/init'
export default {
name: 'dashboard',
data(){
return{
search: '',
singleSelect: false,
subjects: [],
selected: [],
headers: [
{text: 'Control No.', value: 'controlno'},
{text: 'Course No.', value: 'courseno'},
{text: 'Descriptive Title', value: 'descrip_title'},
{text: 'Schedule(In)', value: 'schedin'},
{text: 'Schedule(Out)', value: 'schedout'},
{text: 'Room No.', value: 'roomno'},
{text: 'Days', value: 'days'},
{text: 'Units', value: 'units'}
],
courses: []
}
},
methods:{
enrollSubjects(){
if(this.selected === this.selected){
this.$swal({
title: 'No Course Selected',
text: 'Please select course/s',
type: 'error'
})
}
},
created(){
db.collection('masterlist_courses').get()
.then(snapshot => {
snapshot.forEach(doc => {
let course = doc.data()
course.id = doc.id
this.courses.push(course)
})
})
}
}
}
</script>
I am practicing in firebase and vuetify, I do not know how to push this to the value of the v-data-table. I am having hard time and its not showing anything to the datatable and also there is no error. It's not saying anything after I code the data in the firebase not displaying
You need to use one of the vue.js life cycle hook to trigger the fetch before the component is mounted.
For example the created hook can be used to "run code after an instance is created", as follows:
<script>
// # is an alias to /src
import db from '#/firebase/init'
export default {
name: 'dashboard',
data(){
return{
search: '',
singleSelect: false,
subjects: [],
selected: [],
headers: [
{text: 'Control No.', value: 'controlno'},
{text: 'Course No.', value: 'courseno'},
{text: 'Descriptive Title', value: 'descrip_title'},
{text: 'Schedule(In)', value: 'schedin'},
{text: 'Schedule(Out)', value: 'schedout'},
{text: 'Room No.', value: 'roomno'},
{text: 'Days', value: 'days'},
{text: 'Units', value: 'units'}
],
courses: []
}
},
methods:{
enrollSubjects(){
if(this.selected === this.selected){
this.$swal({
title: 'No Course Selected',
text: 'Please select course/s',
type: 'error'
})
}
}
},
created: function() {
db.collection('masterlist_courses').get()
.then(snapshot => {
snapshot.forEach(doc => {
let course = doc.data()
course.id = doc.id
this.courses.push(course)
})
})
}
}
</script>
Note that if the query to Firestore is going to take some time, you could display a spinner and hide it when the query is done, i.e. in the callback passed to then(), after snapshot.forEach().
You need to define what items should be shown. You have only defined your headers so far. Try it like this for every header you have.
<template v-slot:item.controlno="{ item }">
{{ item.controlno }}
</template>
Hope this helps =)

Resources