Headers in rows in using vuetify - javascript

I am using vuetify 1.0. I am using v-data-table component to display data. But the issue I am facing here is I am not able to figure out how can I display headers in row. Something like this as below.
Name: XYZ
Location: PQR
Number: 000-000-0000
But right now the table looks something like this:
Name Location Number
XYZ
PQR
000-000-0000
In the code below, the manager_array consists of a single object.
<template>
<v-card>
<v-card>
<v-container fluid>
<v-data-table
:headers="headers"
:items="manager_array"
hide-actions
:disable-initial-sort="true">
<template slot="items" slot-scope="props">
<tr>{{ props.item.first_name }}</tr>
<tr>{{ props.item.location }}</tr>
<tr>{{ props.item.number }}</tr>
</template>
</v-data-table>
</v-container>
</v-card>
</v-card>
</template>
<script>
export default {
props: ['manager'],
data () {
return {
manager_array: [],
headers: [
{ text: 'Name', value: 'name'},
{ text: 'Location', value: 'location'},
{ text: 'Number', value: 'number'},
]
}
},
created() {
this.manager_array.push(this.manager)
},
};
</script>

Related

How can I get only the field from a vuetify table to post in axios

How can I get only the field from a vuetify table to post by in axios, I have a table as I show in the following code
<div id="app">
<v-app id="inspire">
<v-card>
<v-card-title>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
label="Search"
single-line
hide-details
></v-text-field>
</v-card-title>
<v-data-table
:headers="headers"
:items="students"
:search="search"
>
<template v-slot:item.status="{ item }">
<v-btn v-if="item.status" #click="add(item)">Add</v-btn>
<v-btn v-else disabled>Temporarily no access</v-btn>
</template>
</v-data-table>
</v-card>
</v-app>
</div>
and from script I have the following code
const app = new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
search: '',
headers: [
{ text: 'Number list', align: 'start', value: 'id'},
{ text: 'Name', align: 'start', value: 'name'},
{ text: 'Options', value: 'status' }
],
students: [
{
id: 1,
name: pedro,
status: activo,
},
{
id: 2,
name: juan,
status: activo,
},
{
id: 3,
name: jose,
status: activo,
},
]
};
},
methods: {
add (item) {
axios.post('http://localhost/list?id=' + item.id)
.then(response => {
this.response = response
}).catch(e => {
console.log(e)
});
},
}
});
What I want to do is that when it is clicked I only sent the id per post with axios but when I click it I get an error in the console that says that item is undefined that is my main error, and as you can see I need it to be first verify that the student's status is active. Below I also add an image of the generated table for further reference.
table reference
Edit
i forgot put
#click="add(item)"
but still doesn´t work, no longer even an error appears in the console even if it has the catch
Try:
<v-btn v-if="item.estado" #click="add(item)">Add</v-btn>
Try 2:
Check first if item is coming through correctly by adding the following line. Maybe this will help in tracking down the problem
<template v-slot:item.status="{ item }">
<p>Debug item text: {{item}}</p>
<v-btn v-if="item.status" #click="add(item)">Add</v-btn>
<v-btn v-else disabled>Temporarily no access</v-btn>
</template>

TextArea Avoid mutating a prop directly since the value will be overwritten

I know that a similar question has already been dealt with on stackoverflow. But I could not put together a solution from the proposed one. I am very ashamed.
The essence is this: I have a component and another one inside it.
The child component-VClipboardTextField is a ready-made configured text-area. I couldn't get the input out of there and I don't get an error when I try to enter it.
Avoid mutating a prop directly since the value will be overwritten
whenever the parent component re-renders. Instead, use a data or
computed property based on the prop's value. Prop being mutated:
"message"
code tabs-item.vue
<template>
<v-container fluid>
<v-row align="center">
<v-col cols="9">
<v-card flat>
<v-card-text>
<h1>Request</h1>
<v-container>
<v-textarea v-model="message"
placeholder="Placeholder"
label="Request"
auto-grow
clear-icon="mdi-close-circle-outline"
clearable
rows="10"
row-height="5"
#click:clear="clearMessage"
></v-textarea>
<v-textarea v-model="response"
placeholder="Placeholder"
label="Request2"
auto-grow
counter
rows="10"
row-height="5"
color="success"
></v-textarea>
<VClipboardTextField ></VClipboardTextField>
<VClipboardTextField isReadOnly></VClipboardTextField>
</v-container>
<v-row>
<v-btn
dark
color="primary"
elevation="12"
justify="end"
float-right
#click="sendRequest"
>
Send Request
</v-btn>
</v-row>
</v-card-text>
</v-card>
</v-col>
<v-col cols="3">
<schema-selector #changeSchema="onChangeSchema"></schema-selector>
</v-col>
</v-row>
</v-container>
</template>
<script>
export default {
name: 'tabs-item',
props: ['response'],
data() {
return {
schema: String,
message: '',
}
},
methods: {
sendRequest() {
const message = {
message: this.message,
method: this.schema.state
}
this.$emit('sendRequest', message)
},
clearMessage() {
this.message = ''
},
onChangeSchema(selectS) {
console.log("get schema: ", selectS.state)
this.schema = selectS
}
},
}
</script>
and child VClipboardTextField.vue
<template>
<v-container>
<v-tooltip bottom
v-model="show">
<template v-slot:activator="{ on, attrs }">
<v-textarea
v-model="message"
:append-outer-icon="'mdi-content-copy'"
:readonly="isReadOnly"
auto-grow
filled
counter
clear-icon="mdi-close-circle-outline"
clearable
label="Response message"
type="text"
#click:append-outer="copyToBuffer"
#click:clear="clearMessage"
></v-textarea>
</template>
<span>Tooltip</span>
</v-tooltip>
</v-container>
</template>
<script>
export default {
name: 'VClipboardTextField',
props: {
isReadOnly: Boolean,
message : { type :String, default: "msg"}
},
data() {
return {
show: false,
// messageLocal: 'Response!',
iconIndex: 0,
}
},
methods: {
copyToBuffer() {
console.log("this: ", this)
navigator.clipboard.writeText(this.message);
this.toolTipChange()
setTimeout(() => this.toolTipChange(), 1000)
},
clearMessage() {
this.message = ''
},
toolTipChange() {
if (this.show)
this.show = false
}
}
}
</script>
I will be glad to see an example of the code that will explain how to correctly solve this problem without crutches!
Thanks.
you cannot modify props in components, if the initial value of message is needed as placeholder (meaning the input might not be empty at the begining), you can store the data in message prop to another data variable and use that as v-model to the textarea.
if there is no initial value for message, just use another data variable for textarea and emit an update for message in a watcher.
in code tabs-item.vue
<VClipboardTextField :message.sync="message"></VClipboardTextField>
and child VClipboardTextField.vue
<template>
<v-container>
<v-tooltip bottom
v-model="show">
<template v-slot:activator="{ on, attrs }">
<v-textarea
v-model="message_slug"
:append-outer-icon="'mdi-content-copy'"
:readonly="isReadOnly"
auto-grow
filled
counter
clear-icon="mdi-close-circle-outline"
clearable
label="Response message"
type="text"
#click:append-outer="copyToBuffer"
#click:clear="clearMessage"
></v-textarea>
</template>
<span>Tooltip</span>
</v-tooltip>
</v-container>
</template>
<script>
export default {
name: 'VClipboardTextField',
props: {
isReadOnly: Boolean,
message : { type :String, default: "msg"}
},
data() {
return {
show: false,
// messageLocal: 'Response!',
iconIndex: 0,
message_slug: '',
}
},
watch: {
message_slug(x) {
this.$emit('update:message', x)
}
},
}
</script>
It will bind the value to message_slug and update the message on parent component when it's value changes.
Instead of watching for change every time, you can only emit when there are changes.
In your tabs-item.vue
<VClipboardTextField v-model="message"></VClipboardTextField>
In your VClipboardTextField.vue component, you can receive the v-model input prop as a "VALUE" prop and assign it to a local data property. That way u can manipulate the local property and emit only when in it is changed!
<template>
<v-container>
<v-tooltip bottom v-model="show">
<template v-slot:activator="{ on, attrs }">
<v-textarea
v-model="message"
:append-outer-icon="'mdi-content-copy'"
:readonly="isReadOnly"
v-on="on"
v-bind="attrs"
auto-grow
filled
counter
clear-icon="mdi-close-circle-outline"
clearable
label="Response message"
type="text"
#click:append-outer="copyToBuffer"
#click:clear="clearMessage"
#change="$emit('input', v)"
></v-textarea>
</template>
<span>Tooltip</span>
</v-tooltip>
</v-container>
</template>
<script>
export default {
name: "VClipboardTextField",
props: {
isReadOnly: { type: Boolean },
value: {
type: String,
},
},
data() {
return {
show: false,
message: this.value,
};
},
};
</script>

update google chart with selected period parameter from v-select

I am looking for a way to update the google bar type chart display
by selecting the period value from v-select.
so far, Initially, my script loaded, call 'async created()' and
get Data from REST API to MongoDB call module and store returned data in posts[].
and then finally save it to chart data array.
The data format is like this
Key
Type
Date (YYYY-MM-DD)
String
success_count
int
failure_count
int
what I wanna do is, each v-select values consist with {name, id} pair.
Is there any way to pass selected 'selectedItem.id' to
script's created(parameter) method or PostService.get_dashboard_Posts(parameter)'s parameter position?
without refreshing the whole page?
below is my CSS code
<template>
<v-app
:style="{ background: $vuetify.theme.themes.light.background }"
style="max-height:100vw;"
>
<v-container style="min-height:100%;">
<v-layout row class="ma-4">
<v-app style="background-color:grey lighten-1:" class="rounded">
<v-row>
<v-col cols="12" md="12" class="ligne">
<v-container>
<v-row>
<v-col cols="12" md="12">
<h1 class="heading mb-2 grey--text">Dashboard </h1>
<v-card>
<template>
<p class="error" v-if="error">{{error}}</p>
<div class = "posts-container">
<div class="post"
v-for="(post,index) in posts"
v-bind:item="post"
v-bind:index="index"
v-bind:key="post._id"
>
</div>
</div>
<div id="app">
<v-col cols="12" md="12">
<v-row>
<v-col cols="12" md="9"><h3 class="subTitle">Number Of Transactions</h3></v-col>
<v-col cols="12" md="3">
<v-select
:items="comboItem"
v-model="selectedItem"
item-text="name"
item-value="id"
label="Period"
single-line
dense
v-on:change=""
return-object>
</v-select>
</v-col>
</v-row>
<GChart
type="ColumnChart"
:data="chartData"
:options="chartOptions"
/>
</v-col>
</div>
</template>
</v-card>
</v-col>
</v-row>
</v-container>
</v-col>
</v-row>
</v-app>
</v-layout>
</v-container>
below is my script code
<script>
// # is an alias to /src
import PostService from "../PostService";
export default {
name: "PostComponent",
data: () => ({
posts:[],
comboItem:[
{
name: 'today',
id: 1
},
{
name: 'last week',
id: 2
},
{
name: 'last month',
id: 3
},
{
name: 'last year',
id: 4
},
],
chartData: [
["date", "success", "failure"]
],
chartOptions: {
chart: {
title: "Company performance",
subtitle: "Sales,Expences,and Profit:2016-2019"
},
hAxis: {
title: "date",
textStyle: {
fontSize:9
}
},
vAxis: {
title: "frequency",
textStyle: {
fontSize:15
}
},
legend: {
position : 'top',
alignment:'center'
}
}
}),
async created() {
try {
this.posts = await PostService.get_dashboard_Posts();
for(var i=0;i<Object.keys(this.posts[0]).length;i++){
this.chartData.push([`${this.posts[0][i]._id.year}-${this.posts[0]
[i]._id.month}-${this.posts[0][i]._id.day}`, this.posts[0][i]._id.success_count, this.posts[0]
[i]._id.failure_count])
}
} catch (err) {
this.error = err.message;
}
},
components: {},
computed: {
theme() {
return this.$vuetify.theme.dark ? "dark" : "light";
}
},
methods:{
}
};
</script>
Yes that is possible,
Basically we need to be able to respond to changes to selectedItem. All the loading currently happens inside the created function, which we cannot run again, so step 1 would be to move or copy the body of the created function to a new method, which we may call load or something. Now we can respond to changed to selectedItem by calling load.
async created() {
await this.load();
},
components: {},
computed: {
theme() {
return this.$vuetify.theme.dark ? "dark" : "light";
}
},
methods: {
async load() {
try {
this.posts = await PostService.get_dashboard_Posts();
for (var i = 0; i < Object.keys(this.posts[0]).length; i++) {
this.chartData.push([`${this.posts[0][i]._id.year}-${this.posts[0]
[i]._id.month}-${this.posts[0][i]._id.day}`, this.posts[0][i]._id.success_count, this.posts[0]
[i]._id.failure_count
])
}
} catch (err) {
this.error = err.message;
}
}
}
There are a few ways we can respond to changes, i'll show you a few:
We can define this behavior on the input element directly in the template:
<v-select
v-model="selectedItem"
...
v-on:change="load(selectedItem.id)"
...
>
</v-select>
Another way to tell vue to respond to changes is by using watchers:
...
async created() {
await this.load();
},
watch: {
selectedItem(newValue) {
this.load(newValue.id);
// At the moment the watcher runs this.selectedItem is already
// the newValue (this.selectedItem === newValue) so we could also
// do this:
this.load(this.selectedItem.id);
}
},
components: {},
...
The last thing that I haven't covered and leave up to you is to supply the selectedItem.id to PostService.get_dashboard_Posts

Search does not work in Vuetify data table when filter function used in headers

I have a Vue component that contains a Vuetify v-data-table component. and it uses the search feature with a <v-text-field>. The problem I'm having is that using the filter function in the headers that are passed as a prop to the data table prevents the search functionality from working.
The data table component uses the body-prepend slot to define select lists to be used for filtering table content.
<v-data-table
show-expand
:headers="headers"
:items="items"
:search="search"
item-key="sow"
hide-default-footer
dense
disable-pagination
>
<template v-slot:top>
<v-toolbar flat color="white">
<v-toolbar-title>{{ title }}</v-toolbar-title>
<v-spacer></v-spacer>
<v-text-field
v-model="search"
prepend-icon="search"
label="Search"
single-line
hide-details
clearable
></v-text-field>
</v-toolbar>
</template>
<template v-slot:body.prepend>
<tr>
<td :colspan="7"></td>
<td v-if="showStatusFilter">
<v-select
v-model="selectedStatuses"
:items="statuses"
:menu-props="{ maxHeight: '400' }"
label="Select Status"
multiple
chips
deletable-chips
small-chips
dense
></v-select>
</td>
<td v-if="showPracticeFilter">
<v-select
v-model="selectedPractices"
:items="practices"
label="Select Practice"
multiple
chips
deletable-chips
small-chips
dense
></v-select>
</td>
<td v-if="showSEFilter">
<v-select
v-model="selectedSEs"
:items="ses"
label="Select SE"
multiple
chips
deletable-chips
small-chips
dense
></v-select>
</td>
</tr>
</template>
</v-data-table>
And then the headers are passed in to the component from the parent component
headers: [
{ text: 'SOW', align: 'left', value: 'sow' },
{ text: 'Firm', value: 'firm' },
{ text: 'Category', value: 'category' },
{ text: '% Complete', value: 'percentComplete' },
{ text: 'Estimated Completion', value: 'estimatedCompletionDate' },
{ text: 'Amount', value: 'amount' },
{
text: 'Status',
value: 'status',
filter: (f) => {
if (this.getSelectedStatuses.length === 0) return true
return this.getSelectedStatuses.indexOf(f + '') !== -1
}
},
{
text: 'Practice',
value: 'practice'
filter: (f) => {
if (this.getSelectedPractices.length === 0) return true
return this.getSelectedPractices.indexOf(f + '') !== -1
}
},
{ text: 'Modified', value: 'modified' },
{ text: 'Actions', value: 'actions' }
],
Vuex is being used to store filtered values so that filters can be used across implementations of the data table component.
Implemented like this, the search field silently dies. However, as soon as I remove the filter functions from the headers array objects, it works just fine. Do I need to implement the filter functions differently? Or should it work like I have it set up? For instance, do I need to dynamically add the filter function to the headers array items within the data table wrapper component instead of passing it in as part of the prop?

I can't display properly v-data-table data: ''Invalid prop: type check failed for prop "items". Expected Array, got Object''

I'm starting a project in which I had to use Vue. I'm actually really new to this, so I'm learning on the go. I do apologize in advance since this question have answered before, however, I didn't really understand the solutions provided, which is why I'm here asking myself.
Well, I was trying to display some data on my Data Table (more specifically, v-data-table from Vuetify). I was able to get the data from the API, but, for some reason it doesn't show me anything. Thanks to Vuex I can see that the mutation worked because on the console on Google Chrome I can see the Array of objects. But as I said, it still does't show me a single thing on the table, it even says 'no data available'. Some errors that I get are things like '[Vue warn]: Invalid prop: type check failed for prop "items". Expected Array, got Object' and 'TypeError: this.items.slice is not a function'.
Here is the code from List.vue
<template>
<v-container id="data-tables" tag="section">
<div class="text-right">
<v-btn class="mx-2" fab dark color="primary" :to="{ name: 'UserCreate' }">
<v-icon dark>mdi-plus</v-icon>
</v-btn>
</div>
<base-material-card
color="indigo"
icon="mdi-vuetify"
inline
class="px-5 py-3"
>
<template v-slot:after-heading>
<div class="display-2 font-weight-light">
Lista de Empleados
</div>
</template>
<v-text-field
v-model="search"
append-icon="mdi-magnify"
class="ml-auto"
label="Search"
hide-details
single-line
style="max-width: 250px;"
/>
<v-divider class="mt-3" />
<v-data-table
:headers="headers"
:items="users"
:search.sync="search"
:sort-by="['name', 'office']"
:sort-desc="[false, true]"
multi-sort
>
<template v-slot:item.actions="{ item }">
<v-icon small class="mr-2" #click="editItem(item)">
mdi-eye
</v-icon>
<v-icon
small
class="mr-2"
#click="editItem(item)"
:to="{ name: 'UserUpdate' }"
>
mdi-pencil
</v-icon>
<v-icon small #click="deleteItem(item)">
mdi-delete
</v-icon>
</template>
</v-data-table>
</base-material-card>
</v-container>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'UsersTable',
data() {
return {
headers: [
{
text: 'Nombre',
value: 'empleado.nombre',
},
{
text: 'Apellido',
value: 'empleado.apellido',
},
{
text: 'Dirección',
value: 'empleado.direccion',
},
{
text: 'Correo Electrónico',
value: 'email',
},
{
text: 'Teléfono',
value: 'empleado.telefono',
},
{
sortable: false,
text: 'Actions',
value: 'actions',
},
],
loader: true,
search: undefined,
}
},
created() {
this.$store.dispatch('users/fetchUsers')
},
computed: {
...mapState(['users']),
},
methods: {},
mounted() {},
}
</script>
And the code from user.js, where the fetchUsers it's coming from.
import auth from '#/api/auth'
export const namespaced = true
export const state = {
users: [],
}
export const mutations = {
SET_USERS(state, users) {
state.users = users
},
}
export const actions = {
fetchUsers({ commit, dispatch }) {
auth
.getAllAccounts()
.then((response) => {
commit('SET_USERS', response.data)
})
.catch((error) => {
const notification = {
type: 'error',
message: 'There was a problem fetching users: ' + error.message,
}
dispatch('notification/add', notification, { root: true })
})
},
}
Thanks in advance.
You are not getting the correct user from vuex, because is namespaced, change to:
computed: {
...mapState('users',['users']),
},
MapState helper dosen't work the same way like the other helpers because the state module isn't registred in the global namespace. So namespacing your module will help or you do it in this way:
computed: {
...mapState({
users: state => state.FilenameOfYourModule.users
})
}

Categories

Resources