How to show an icon only when certain tab is selected? - vue.js

For this website I have two login tabs as seen in the image below, and right now it's hard to understand which login tab is selected.
I'm trying to display an icon next to the selected tab, but currently it shows the icon for both tabs. So overall I'm trying to show the icon only for the tab that is selected and if I change the tab, it hides it from the previously selected tab and shows it to the current one.
This is the whole code that I have -
<template>
<v-main id="login">
<v-container fill-height fluid>
<v-layout align-center justify-center>
<v-flex md4 sm8 xs12>
<v-card class="elevation-12">
<v-toolbar color="primary" dark>
<v-toolbar-title>
<v-icon left> mdi-login-variant </v-icon>
{{ $t("welcome") }}
</v-toolbar-title>
</v-toolbar>
<v-divider />
<v-tabs v-model="selectedTab" grow hide-slider>
<v-tab
v-for="(tab, i) in tabs"
:key="i"
:class="{
'primary white--text': tab == selectedTab,
caption: tab != selectedTab,
}"
:href="`#${tab}`"
class="pa-0"
>
{{ tab }}
//This is the icon line that I added
<v-icon right >mdi-check-circle-outline</v-icon>
</v-tab>
<v-tab-item
v-for="(tab, i) in tabs"
:key="i"
:value="tab"
reverse-transition="scale-transition"
transition="scale-transition"
>
<v-divider />
<v-card-text>
<v-form #submit.prevent="login">
<v-text-field
v-model.lazy="username"
:label="$t('username')"
:prepend-inner-icon="
tab === 'Windows' ? 'mdi-windows' : 'mdi-account'
"
:rules="[username !== null || required]"
name="username"
outlined
placeholder=" "
type="text"
/>
<v-text-field
v-model.lazy="password"
:label="$t('password')"
:rules="[password !== null || required]"
name="password"
outlined
placeholder=" "
prepend-inner-icon="mdi-lock"
type="password"
/>
<!-- If error, rended error component -->
<error-view
v-if="error"
:error="error"
:is-login="true"
class="pa-0"
/>
<v-card-actions class="pa-0">
<v-spacer />
<v-btn :loading="loading" color="primary" type="submit">
{{ $t("submit") }}
</v-btn>
</v-card-actions>
</v-form>
</v-card-text>
</v-tab-item>
</v-tabs>
<div id="version-div">
<app-version />
</div>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-main>
</template>
<script>
import AppVersion from "#/components/version";
const errorView = () => import("#/components/errorView");
export default {
name: "Login",
components: {
errorView,
AppVersion,
},
data() {
return {
tabs: ["Windows", "Standard"],
selectedTab: "Standard",
username: null,
password: null,
loading: false,
error: null,
required: (value) => !!value || this.$t("req"),
};
},
methods: {
resetForm(value) {
this.username = this.password = value;
},
login() {
if (!this.username || !this.password) {
this.error = this.$t("warn");
this.resetForm(null);
} else {
this.loading = true;
const encodedPass = window.btoa(
unescape(encodeURIComponent(this.password))
);
this.$store
.dispatch("retrieveUser", {
username: this.username,
password: encodedPass,
outside: this.selectedTab === "Windows" ? false : true,
})
.then(() => {
this.$router.push({ name: "home" });
this.error = null;
})
.catch((error) => {
this.error = error;
})
.finally(() => {
this.resetForm("");
this.loading = false;
});
}
},
},
};
</script>
Thank you in advance!

You've actually already implemented the solution in a different part of your code.
Apply the same conditioning as you do to the class binding on 'primary white--text'. The v-icon can be conditionally rendered based on the tab selected.
<v-icon v-if="tab === selectedTab" right >mdi-check-circle-outline</v-icon>

Related

How do I capture the value of the prop in the text field?

I have a prop and currently am able to get the data of the prop, Am trying a way to capture the item of the prop when saving the form.
Is there a way where i can take the value and pass if in a hidden text-area and bind the data to the vmodel?
Any help I appreciate.
<v-dialog v-model="dialog" persistent max-width="800">
<template v-slot:activator="{ on }">
<v-btn dark v-on="on" color="primary" round> Make payment </v-btn>
</template>
<v-card>
<v-card-title class="headline primary">
<span class="white--text">Add a new Doctor Payment Record {{ queueId }}</span>
<v-btn icon dark #click.native="dialog = false" absolute right>
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text>
<users-search
:leave-selected="true"
idOnly
label="Select Doctor"
#results="setDoctor"
>
</users-search>
<div class="row px-3">
<v-autocomplete
class="px-3 col-sm-8"
v-model="expense.bank"
v-if="banks.data"
:items="banks.data"
outline
chips
label="Select bank"
item-text="name"
item-value="id"
>
</v-autocomplete>
<v-text-field
class="px-3 col-sm-8"
outline
flat
v-model="expense.amount"
type="number"
#input="expense.percentage()"
required
label="Amount *"
persistent-hint
/>
</div>
<v-text-field
class="px-3"
outline
flat
v-model="expense.total_paid"
required
label="amount paid"
persistent-hint
/>
<v-text-field
class="px-3"
outline
flat
:value="setQueue"
v-model="expense.queueId"
required
:label=queueId
persistent-hint
/>
<v-alert :value="true" type="error" v-if="errors.any()">
<div v-html="errors.display()"></div>
</v-alert>
<v-layout row wrap>
<v-flex xs12>
<v-btn
color="success"
:loading="saveLoader"
#click="recordExpense()"
>save</v-btn
>
</v-flex>
</v-layout>
</v-card-text>
</v-card>
</v-dialog>
</template>
<script>
import NewUser from "#finance/libs/users/NewUser";
import {mapActions, mapGetters} from "vuex";
export default {
props: [
'queueId'
],
data: () => ({
dialog: false,
expense: new NewUser(),
saveLoader: false,
}),
computed: {
...mapGetters({
banks: "getBanks",
}),
balance: function () {
return parseFloat(10);
},
submitted() {
return this.expense.form.submitted;
},
contaminated() {
return this.expense.form.errorDetected;
},
errors() {
return this.expense.form.errors;
},
},
watch: {
submitted(v) {
if (v) {
this.saveLoader = false;
}
},
contaminated() {
this.saveLoader = false;
},
},
methods: {
...mapActions({
fetchBanks: "setBanks",
}),
setDoctor(user) {
this.expense.doctor_id = user.id;
},
setQueue(){
console.log(this.queueId);
this.expense.queueId = this.queueId;
},
async recordExpense() {
this.saveLoader = true;
let response = await this.expense.saveExpense();
this.saveLoader = false;
if (response) {
this.dialog = false;
this.$emit("expenseCreated");
}
},
},
mounted() {
this.fetchBanks();
}
};
</script>
The prop queueId i also want to store it along with the user information from the form.
Try this one, it should work:
<template>
<textarea v-model="hiddenValue" :style="{ display: 'none' }"></textarea>
</template>
<script>
export default {
props: [ 'queueId' ],
data() {
return {
hiddenValue: this.queueId
}
}
}
</script>
In case you will no need the prop to be modified, please bind the texarea value to the prop directly:
<textarea hidden v-model="queueId" :style="{ display: 'none' }></textarea>

vue.js not responding to property of object changing

<v-container class="text-center hyp-container pa-4">
<v-row>
<button #click="toggleForm">Add new</button>
</v-row>
<v-row>
<v-dialog v-model="showConfirmDelete" width="500">
<v-card>
<v-card-title class="headline grey lighten-2">
Confirm
</v-card-title>
<v-card-text>
<v-spacer></v-spacer>
Are you sure you want to delete this target?
</v-card-text>
<v-card-actions>
<v-btn color="secondary" #click="showConfirmDelete = false"
>Cancel</v-btn
>
<v-spacer></v-spacer>
<v-btn color="primary" #click="doDeleteTarget">Delete</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<v-dialog v-model="showTargetForm" width="800">
<v-card>
<form #submit="saveTarget">
<v-card-title class="headline grey lighten-2">
Add Slack target
</v-card-title>
<v-card-text>
<v-spacer></v-spacer>
<v-text-field
label="Target Name"
v-model="target.name"
#keyup="modifyTargetName"
></v-text-field>
<v-text-field
label="Webhook URL"
v-model="target.webhook"
></v-text-field>
<v-text-field
label="Slack Channel"
v-model="target.channel"
#keyup="modifyTargetChannel"
></v-text-field>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-btn color="secondary" #click="showTargetForm = false"
>Close</v-btn
>
<v-spacer></v-spacer>
<v-btn color="secondary" #click="target = {}">Clear</v-btn>
<v-btn color="secondary" #click="testTarget">Test</v-btn>
<v-btn color="primary" type="submit">
Save
</v-btn>
</v-card-actions>
</form>
</v-card>
</v-dialog>
</v-row>
<v-row>
<ol>
<li v-for="target in targets" :key="target.id">
<v-card>
<v-card-text>
<v-card-actions>
<v-btn icon #click="toggleShow(target)">
<v-icon>{{
target.show ? "mdi-chevron-up" : "mdi-chevron-down"
}}</v-icon>
</v-btn>
<div class="title">
{{ target.name }}
{{ target.show }}
</div>
</v-card-actions>
<v-expand-transition>
<div v-if="target.show">
<v-divider></v-divider>
<v-card-text>
{{ target.channel }}
edit
delete
<div class="truncate">{{ target.webhook }}</div>
</v-card-text>
</div>
</v-expand-transition>
</v-card-text>
</v-card>
</li>
</ol>
</v-row>
</v-container>
</template>
<script>
export default {
name: "PersonalTargetsSelector",
props: {
disabled: {
type: Boolean,
default: false,
},
},
data: () => ({
showTargetForm: false,
target: {},
targets: [],
showConfirmDelete: false,
targetToDelete: {},
show: {},
}),
async mounted() {},
methods: {
toggleShow(target) {
console.log(target.show);
this.target.show = !Boolean(target.show);
console.log(target.show);
},
handleClickCancel: function () {
this.target = {};
this.showTargetForm = false;
this.handlePageTrackerEvent(
EVENT_CATEGORIES.personalTargets,
EVENT_ACTIONS.clicked,
"Edit Mode - Cancel a Personal Target"
);
},
saveTarget(e) {
e.preventDefault();
console.log("Save target....", this.target);
if (this.target.id) {
// update
this.targets.map(
(t) =>
this.targets.find((t) => t.id === this.target.id) || this.target
);
} else {
// create
this.target.id = Math.random().toString(26).slice(2);
this.targets.push(this.target);
}
this.target = {};
this.showTargetForm = false;
},
editTarget(target) {
this.target = target;
this.showTargetForm = true;
},
testTarget() {
console.log("test target...");
},
confirmDeleteTarget(target) {
this.showConfirmDelete = true;
this.targetToDelete = target;
},
doDeleteTarget() {
this.targets = this.targets.filter(
(t) => t.id !== this.targetToDelete.id
);
this.showConfirmDelete = false;
},
modifyTargetChannel(e) {
const { value } = e.target;
console.log(value);
this.target.channel = value.indexOf("#") === -1 ? "#" + value : value;
},
modifyTargetName(e) {
const { value } = e.target;
this.target.name =
value.indexOf("[Personal]") === -1 ? "[Personal] " + value : value;
},
toggleForm(e) {
e.preventDefault();
this.showTargetForm = !this.showTargetForm;
},
handleClickClose() {
this.forceClose = new Date().toISOString();
},
setConfirmationShow(value) {
this.resetConfirmationShow = value;
},
handlePageTrackerEvent(category, action, name) {
let _paq = (window._paq = window._paq || []);
_paq.push(["trackEvent", category, action, name]);
pageTrackerLogger(
"Page Tracker Event " +
category +
" " +
action +
" " +
name +
" logged."
);
},
},
watch: {
"target.show"(newValue) {
console.log(newValue);
},
},
};
</script>
<style>
.v-application ol {
list-style-type: none;
padding: 0;
}
</style>
the log shows its changing but the UI does not update its value when i put it in {{target.show}}
You're updating target through the props passed to function. Instead:
methods: {
toggleShow(target) {
console.log(target.show);
this.target.show = !Boolean(this.target.show);
console.log(target.show);
},
}

Passing array to component, devtools sees it, the component does not

I'm passing an array to a component but the component sees the array as undefined. Here is the parent calling the component...
<FileList ref="files" class="ma-3 pa-0" :passFiles="true" :passedFiles="header.files"></FileList>
Vue devtools sees the array, it is valid. As seen in the screenshot below:
Yet in my created hook in the controller, it shows this.passedFiles as undefined. (this.passFiles, however, shows correctly as true.)
created(){
console.log(this.passFiles,this.passedFiles); //this.passedFiles shows as undefined
window.addEventListener("resize", this.onResize);
},
I dumped the array right before it gets sent to the component, and it is there, see screenshot:
I tried this just to make sure, and it gets passed to the array fine:
:passedFiles="[{0: '1'}]"
I'm pulling my hair out here. Here is the full component, it is long but it shows you everything
<template>
<div>
<div class="text-center pa-10" v-show="loading">
<v-progress-circular
:size="35"
:width="3"
color="primary"
indeterminate
></v-progress-circular>
</div>
<v-data-table
v-show="!loading"
:headers="showActions ? headers : headersRead"
:items="orderedFiles"
:items-per-page="paginate"
:footer-props="{'items-per-page-options':[paginate, 15, 30, 50, 100, -1]}"
:hide-default-footer="oneFileOnly"
class="elevation-1 custom-rounded-box ma-0 pa-0"
ref="aWidth"
:style="forceHeight&&$vuetify.breakpoint.mdAndUp ? 'height:'+forceHeight+'px;' : ''"
>
<template slot="no-data">
<div>There are currently no files here</div>
</template>
<template v-slot:item.description="{item, index}">
<v-row
no-gutters
style="flex-wrap: nowrap;"
>
<v-col
cols="12"
md="11"
class="flex-grow-0 flex-shrink-0"
>
<v-tooltip bottom v-if="item.description">
<template v-slot:activator="{ on, attrs }">
<a
v-if="item.gdoc"
style="text-decoration: none; color: orange;"
v-bind="attrs"
v-on="on"
#click.prevent="gdocDialog = true;editingFile = item"
class="d-block text-truncate"
:style="$vuetify.breakpoint.mdAndUp ? 'max-width:'+aWidth+'px;' : 'max-width:'+bWidth+'px;'"
>
{{item.description}}
</a>
<a
v-else
:href="'/getFile?id='+item.id"
style="text-decoration: none; color: orange;"
v-bind="attrs"
v-on="on"
class="d-block text-truncate"
:style="$vuetify.breakpoint.mdAndUp ? 'max-width:'+aWidth+'px;' : 'max-width:'+bWidth+'px;'"
>
{{item.description}}
</a>
</template>
<span>{{item.file_name_original}}</span>
</v-tooltip>
<div v-else>
<a
v-if="item.gdoc"
style="text-decoration: none; color: orange;"
#click.prevent="gdocDialog = true;editingFile = item"
class="d-block text-truncate"
:style="$vuetify.breakpoint.mdAndUp ? 'max-width:'+aWidth+'px;' : 'max-width:'+bWidth+'px;'"
>
{{item.file_name_original}}
</a>
<a
v-else
:href="'/getFile?id='+item.id"
style="text-decoration: none; color: orange;"
class="d-block text-truncate"
:style="$vuetify.breakpoint.mdAndUp ? 'max-width:'+aWidth+'px;' : 'max-width:'+bWidth+'px;'"
>
{{item.file_name_original}}
</a>
</div>
</v-col>
<v-col
cols="12"
md="1"
style="min-width: 30px; max-width: 30px;"
class="flex-grow-1 flex-shrink-0"
v-show="$vuetify.breakpoint.mdAndUp"
>
<v-edit-dialog
:return-value.sync="item.description"
#save="editFileInline()"
#open="inlineEditOpen(item, index)"
v-if="showActions"
>
<template v-slot:input>
<v-text-field
ref="inline_file"
v-model="editingFile.description"
label="Edit"
single-line
counter
></v-text-field>
</template>
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-icon
small
class="ml-2"
color="orange"
v-bind="attrs"
v-on="on"
width="100%"
>
mdi-pencil
</v-icon>
</template>
<span>Edit the file description</span>
</v-tooltip>
</v-edit-dialog>
</v-col>
</v-row>
</template>
<template v-slot:item.icon="{ item }">
<v-icon
:color="item.icon_color"
>
{{item.icon}}
</v-icon>
</template>
<template v-slot:item.uploaded="{ item }">
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<div v-bind="attrs"
v-on="on">
{{item.date_difference}}
</div>
</template>
<span>
<v-avatar
size="26px"
class="mr-2"
>
<img
:src="'/img/profile-pictures/'+item.user.profile_photo_thumb"
>
</v-avatar>
{{item.pretty_date}} by {{item.user.full_name}}</span>
</v-tooltip>
</template>
<template v-slot:item.actions="{item}" v-if="showActions">
<v-tooltip bottom>
<template v-slot:activator="{ on, attrs }">
<v-icon
small
color="red"
#click="showDeleteDialog(item)"
v-bind="attrs"
v-on="on"
>
mdi-delete
</v-icon>
</template>
<span>Delete</span>
</v-tooltip>
</template>
</v-data-table>
<!-- Upload modal -->
<v-dialog
v-model="fileUploadDialog"
max-width="500px"
width="500px"
:transition="transitionSiteWide()"
persistent
v-if="showActions"
>
<v-card>
<v-progress-linear
indeterminate
color="yellow darken-2"
v-show="fileUploadProcess"
></v-progress-linear>
<v-toolbar
dark
class="primary"
dense
elevation="0"
>
<v-icon class="mr-2">mdi-cloud-upload</v-icon>
<v-toolbar-title class="text">Upload File(s)</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-card-text class="pt-3" v-show="!fileUploadGDoc">
<template>
<v-file-input
small-chips
:label="!oneFileOnly ? 'Upload multiple files by clicking here' : 'Click here to upload a file'"
type="file"
ref="files"
:accept="acceptedFiles()"
#change="onFilePicked()"
:key="componentKey"
show-size
counter
:multiple="!oneFileOnly"
:rules="!oneFileOnly ? rules : rulesSingle"
></v-file-input>
</template>
</v-card-text>
<v-card-text class="pt-3" v-show="fileUploadGDoc">
<v-text-field
ref="gdoc_description"
v-model="gdoc_description"
label="Description"
:rules="gdoc_description_rules"
prepend-icon="mdi-pencil"
></v-text-field>
<v-text-field
ref="gdoc_link"
v-model="gdoc_link"
label="Link to your Google Document"
:rules="gdoc"
prepend-icon="mdi-google-drive"
></v-text-field>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
text
#click="ok"
>
Close
</v-btn>
<v-btn
class="primary"
text
v-show="fileUploadButton"
#click="uploadFiles()"
:loading="fileUploadProcess"
>
Upload
</v-btn>
<v-btn
class="primary"
text
v-show="gdocValidated()"
#click="uploadFiles()"
:loading="fileUploadProcess"
>
Attach
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- Delete dialog -->
<v-dialog
v-if="showActions"
v-model="deleteFileConfirm"
max-width="400px"
:transition="transitionSiteWide()"
>
<v-card elevation="0">
<v-progress-linear
indeterminate
color="yellow darken-2"
v-show="deleteFileLoading"
></v-progress-linear>
<v-toolbar
dark
class="primary"
dense
elevation="0"
>
<v-icon class="mr-2">mdi-text-box-minus</v-icon>
<v-toolbar-title class="text">{{editingFile.description ? editingFile.description : editingFile.file_name_original}}</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-card-text class="pb-0">
<v-container>
<p>Are you sure you want to delete this file?</p>
<p>{{editingFile.description ? editingFile.description : editingFile.file_name_original}}
will be removed from the system.</p>
</v-container>
</v-card-text>
<v-card-actions>
<v-btn
text
#click="deleteFileConfirm = false"
>
Close
</v-btn>
<v-spacer></v-spacer>
<v-btn
class="primary"
text
#click="deleteSet()"
>
Yes, delete this file
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- Gdoc dialog -->
<v-dialog
v-model="gdocDialog"
max-width="1000px"
width="100%"
:transition="transitionSiteWide()"
>
<v-card elevation="0">
<v-toolbar
dark
color="teal"
dense
elevation="0"
>
<v-icon class="mr-2">mdi-google-drive</v-icon>
<v-toolbar-title class="text">{{editingFile.description ? editingFile.description : editingFile.file_name_original}}</v-toolbar-title>
<v-spacer></v-spacer>
</v-toolbar>
<v-card-text class="pa-0">
<iframe ref="gdocIframe" :src="editingFile.file_name_original" :style="'height:'+iframeHeight+'px;width:100%;border:0'"></iframe>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
text
#click="gdocDialog = false"
>
Close
</v-btn>
<v-btn
class="primary"
text
link
#click="openGdoc(editingFile.file_name_original);"
>
Open in new window
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
<script>
export default {
props: {
type: String,
id: [Number, String],
paginate: Number,
fileUploadDialog: Boolean,
fileUploadGDoc: Boolean,
ok: Function,
showActions: Boolean,
forceHeight: { type: Number, default: 0 },
oneFileOnly: Boolean,
passFiles: Boolean,
passedFiles: Array,
},
data () {
return {
headers: [
{
text: '',
align: 'start',
sortable: false,
value: 'icon',
width: '20px'
},
{ text: 'Description', value: 'description', sortable: false, },
{ text: 'Uploaded', value: 'uploaded', width: '150px' },
{ text: 'Actions', value: 'actions', sortable: false, width: '80px', align: 'center' },
],
headersRead: [
{
text: '',
align: 'start',
sortable: false,
value: 'icon',
width: '20px'
},
{ text: 'Description', value: 'description', sortable: false, },
{ text: 'Uploaded', value: 'uploaded', width: '150px' },
],
rules: [
files => !files || !files.some(file => file.size > 20_097_152) || 'Each file cannot exceed 20mb',
],
rulesSingle: [
],
gdoc: [
(value) => !!value || "Required",
(value) => this.isURL(value) || "URL is not valid",
],
gdoc_description_rules: [
(value) => !!value || "Required",
],
files: [],
fileUploadButton: false,
deleteFileConfirmLoading: false,
fileUpload: false,
fileUploadProcess: false,
componentKey: 0,
postFormData: new FormData(),
editingFile: {
description: null,
index: null,
file_name_original: null,
},
deleteFileConfirm : false,
deleteFileLoading: false,
gdoc_link: null,
gdoc_description: null,
gdocDialog: false,
iframeHeight: 0,
aWidth: 0,
loading: true,
}
},
computed:{
orderedFiles: function () {
return _.orderBy(this.files, 'created_at', 'desc')
},
},
watch: {
files: {
immediate: false,
handler(){
if(this.files){
this.total = this.files.length;
this.$emit('totalFiles', this.total);
}else{
this.total = 0;
}
},
},
id: {
immediate: false,
handler(){
this.getFiles()
},
}
},
methods: {
async getFiles(){
this.loading = true;
await axios
.get('/app/files/getFiles?id=' + this.id + '&type=' + this.type)
.then(response => {
if (response.data.length) {
this.files = response.data;
this.$emit('totalFiles', this.files.length);
this.resize();
this.loading = false;
} else {
this.files = [];
this.$emit('totalFiles', 0);
this.loading = false;
}
})
.catch(error => {
this.majorError();
})
.finally()
},
onFilePicked(e) {
this.postFormData = new FormData();
if(this.$refs.files.validate()){
this.fileUploadButton = true;
}
this.postFormData = new FormData();
for(let key in event.target.files){
if(key >= 0){
this.postFormData.append( 'files[]', event.target.files[key]);
}
}
},
async uploadFiles(){
this.fileUploadProcess = true;
this.postFormData.append('type', this.type);
this.postFormData.append('id', this.id);
this.postFormData.append('gdoc', this.fileUploadGDoc);
this.postFormData.append('gdoc_link', this.gdoc_link);
this.postFormData.append('gdoc_description', this.gdoc_description);
const res = await this.callApi('post', '/app/files/uploadFiles', this.postFormData);
if(res.status===200){
this.componentKey++; //reset trick
this.snackbar(res.data.msg,res.data.type);
this.ok();
this.fileUploadProcess = false;
this.gdoc_link = null;
this.gdoc_description = null;
this.$refs.gdoc_link.reset()
this.$refs.gdoc_description.reset()
if(res.data.files){
for (const file of res.data.files) {
this.files.push(file);
}
}
this.resize();
this.fileUploadButton = false;
}else{
this.fileUploadProcess = false;
this.snackbar(res.data.msg, res.data.type);
}
},
inlineEditOpen (item) {
let obj = { ...item, editingIndex: this.files.indexOf(item) }
this.editingFile = obj;
},
async editFileInline(){
const file = Object.assign({}, this.editingFile); //Turn array into object for laravel
const res = await this.callApi('post', '/app/files/updateFile',
{file: file});
if(res.status===201){
this.files[this.editingFile.editingIndex].description = this.editingFile.description;
this.snackbar(this.editingFile.description + " has been edited successfully", 'success');
this.resize();
}else{
if(res.status===422){
for(let i in res.data.errors) {
this.snackbar(res.data.errors[i][0], 'error');
}
}else{
this.snackbar("There has been an error, we don't have any more information for you", 'error');
}
}
},
showDeleteDialog(file){
this.deleteFileConfirm = true;
let obj = { ...file, index: this.files.indexOf(file)}
this.editingFile= obj;
},
async deleteSet(){
this.deleteFileLoading = true;
const res = await this.callApi('post', '/app/files/deleteFile', this.editingFile);
if(res.status===200){
this.files.splice(this.editingFile.index, 1);
this.snackbar("File deleted successfully", 'success');
this.deleteFileConfirm = false;
}else{
if(res.status===422){
this.snackbar(res.data.msg, 'error');
}
}
this.deleteFileLoading = false;
},
gdocValidated(){
if(this.gdoc_link&&this.$refs.gdoc_link.validate()&&this.gdoc_description){
return true;
}
},
openGdoc(url){
window.open(url, '_blank').focus();
},
onResize() {
this.iframeHeight = window.innerHeight - 220;
if(this.showActions){
this.aWidth = this.$refs.aWidth.$el.clientWidth - 355;
this.bWidth = this.$refs.aWidth.$el.clientWidth - 150;
}else{
this.aWidth = this.$refs.aWidth.$el.clientWidth - 270;
this.bWidth = this.$refs.aWidth.$el.clientWidth - 65;
}
},
resize(){
setTimeout(() => window.dispatchEvent(new Event('resize')), 1);
},
},
async mounted(){
if(this.passFiles){
this.files = this.passedFiles;
//console.log(this.passedFiles,this.files)
this.loading = false;
}else{
this.getFiles();
}
this.onResize();
this.resize();
},
created(){
console.log(this.passFiles,this.passedFiles); //this.passedFiles shows as undefined
window.addEventListener("resize", this.onResize);
},
destroyed(){
window.removeEventListener("resize", this.onResize);
this.editingFile = null;
},
}
</script>
What am I missing here?

How to programatically close a Veutify dialog

Hello everyone i was searching on the vuetify documentation a function or something like that to close a form dialog just after getting the axios response with the status 200 ..
i don't if there's a way to get a dialog instance and use a close() method on it like the bootstrap modals
here's my code :
template code
<template>
<v-dialog justify-center max-width="500px">
<template v-slot:activator="{on}">
<v-icon
small
v-on="on"
>
mdi-pencil
</v-icon>
</template>
<v-card>
<form #submit.prevent="submit">
<v-card-text>
<v-text-field
v-model="name"
label="Name"
required
></v-text-field>
<v-text-field
v-model="email"
label="E-mail"
required
></v-text-field>
<v-text-field
v-model="password"
label="password"
required>
</v-text-field>
</v-card-text>
<v-card-actions>
<v-btn
color="blue darken-1"
text
>close</v-btn>
<v-btn
color="blue darke-1"
text
type="submit"
>apply</v-btn>
</v-card-actions>
</form>
</v-card>
</v-dialog>
</template>
and here's the script
<script>
export default {
data () {
return {
name: '',
email: '',
password: ''
}
},
methods: {
submit() {
let Data = new FormData()
Data.append('name', this.name)
Data.append('email', this.email)
Data.append('password', this.password)
axios.post('http://stage.test/admin/users', Data)
.then(Response => {
if (Response.status === 200) {
}
})
}
},
}
</script>
Try to bind dialog component to a data property called open as follows :
<template>
<v-dialog v-model="open" justify-center max-width="500px">
<template v-slot:activator="{on}">
<v-icon
small
v-on="on"
>
mdi-pencil
</v-icon>
.....
then in then callback assign false to this.open
<script>
export default {
data () {
return {
open:false,
name: '',
email: '',
password: ''
}
},
methods: {
submit() {
let Data = new FormData()
Data.append('name', this.name)
Data.append('email', this.email)
Data.append('password', this.password)
axios.post('http://stage.test/admin/users', Data)
.then(Response => {
if (Response.status === 200) {
this.open=false
}
})
}
},
}
</script>

Object in array is undefined in vue

I need help as the array “items1” works when “console.log(this.items1)”
However, it is undefined when “console.log(this.items1[0])”. How can I solve this? I really have no idea what is going. Ultimately, I want to gather item.text whenever user selects the tab from v-tabs. Using item.text, I am able to filter the data in db. Is there a way to gather the user input whenever user selects tab?
<template>
<v-layout>
<v-container flat grid-list-lg>
<v-layout row wrap class="flex_box feature_products">
<v-flex xs12>
<h2 class="text-xs-center feature_products_title">Check Our <span>Delicious Menu</span></h2>
</v-flex>
<v-flex xs12>
<v-card>
<v-toolbar flat>
<template v-slot:extension>
<v-tabs v-model="model" centered slider-color="yellow">
<v-tab v-for="(item, index) in items1" :key="index" :href="`#tab-${index}`">
{{ item.text }}
</v-tab>
</v-tabs>
</template>
</v-toolbar>
<v-tabs-items v-model="model">
<v-tab-item v-for="(item, index) in items1" :key="index" :value="`tab-${index}`">
<!-- your this code displays the product information, but there is no way to filter the product by category -->
<v-layout row wrap class="flex_box feature_products">
<v-flex xs12 sm3 md3 lg3 xl2 class="flex_item" v-for="(product,index) in products" :key="index">
<v-card flat v-if="product.category_name == item.text">
<v-card class="overlay_container flex_wrap pa-2">
<v-img :src="product.image" contain></v-img>
<div style="width:100%;" class="flex_bottom text-xs-center pb-2">
<h3 class="headline text-xs-center grey--text text--darken-3">{{product.item_name}}</h3>
<h4 class="grey--text text--darken-3">{{currency}}{{product.price}}</h4>
</div>
<v-card class="overlay">
<h2 style="vertical-align:middle;">{{product.item_name}}</h2>
<v-list class="details">
<v-list-tile-action>
<v-btn style="width:100%" :to="'/product/' + product.id">Details</v-btn>
</v-list-tile-action>
<v-list-tile-action>
<v-btn style="width:100%" class="main_color white--text" #click="addToCart(product)">Add To Cart</v-btn>
</v-list-tile-action>
</v-list>
</v-card>
</v-card>
</v-card>
<v-card v-else>
</v-card>
</v-flex>
</v-layout>
</v-tab-item>
</v-tabs-items>
</v-card>
</v-flex>
</v-layout>
</v-container>
</v-layout>
</template>
<script>
import Vue from 'vue'
import firebase from "firebase";
import moment from 'moment'
import db, {functions} from '#/firebase/init'
import MenuNavbar from '#/components/shop/navbar/MenuNavbar'
export default {
data(){
// Show All Categories
let ref = db.collection("item_categories");
ref.onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if (change.type == "added") {
let doc = change.doc;
this.items1.push({
icon: doc.data().category_icon,
text: doc.data().category_name,
link:'CatProduct',
category:doc.data().category_name,
text1: 'Category Name: ' + doc.data().category_name
});
}
});
});
return{
model:'tab-2', // select your default tab here
currency:null,
products:[],
cart:this.$store.getters.cart,
items1:[],
}
},
components: {
MenuNavbar
},
methods: {
productInCart(product) {
const cartItems = this.cart
for (let i = 0; i < cartItems.length; i++) {
if (cartItems[i].product.id === product.id) {
return i
}
}
return null
},
addToCart(product, quantity){
const index = this.productInCart(product)
const productQuantity = (!quantity || quantity < 1) ? 1 : parseInt(quantity)
if (index === null) {
var items = {
product: product,
quantity: productQuantity
}
//this.$store.commit('catalog/updateCart', items)
this.$store.commit('updateCart', items)
}else {
if(!quantity){
// If item is already into the cart then add++ quantity
this.$store.commit('increaseQuantity', index)
}else{
// When quantity updated manually
}
}
},
removeCart(index){
this.$store.commit('removeCart', index)
},
},
computed:{
counter(){
return this.$store.getters.counter
},
},
getTabText(text){
return text
},
created(){
var db = firebase.firestore();
// Current Currency
db.collection("settings").doc('config').onSnapshot(doc =>{
this.currency = doc.data().currency
})
console.log(this.items1[0])
// Show All Items
let cref = db.collection('items').orderBy('timestamp', 'desc').where("featured", "==", true)
cref.onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if(change.type == 'added'){
let doc = change.doc
this.products.push({
id:doc.id,
item_name:doc.data().item_name,
image:doc.data().image,
category_name:doc.data().item_category,
price:doc.data().price,
quantity:doc.data().quantity,
timestamp:moment(doc.data().timestamp).fromNow('lll')
})
}
})
})
}
}
</script>