How to programatically close a Veutify dialog - vue.js

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>

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 & Django - axios post response status 200 but called catch error

i'm learning Vue.js and Django.
I want to post user info.
axios response status 200 code, but catch function is called.
If the response is successful, the login 'success dialog' is called , but the login 'fail dialog' is also called.
this image is console log.
enter image description here
please help me!
here is my code.
<script>
// LoginDialog.vue
import axios from "axios";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.xsrfHeaderName = "X-CSRFToken";
export default {
name: "LoginDialog",
components: {},
props: {
dialog: Boolean,
},
data() {
return {
showPassword: false,
dialogClose: {
success: false,
fail: false,
},
me: {},
};
},
setup() {},
created() {},
mounted() {},
unmounted() {},
computed: {
dialogOpen: {
get() {
return this.dialog;
},
set(val) {
this.$emit("close", val);
},
},
},
methods: {
save() {
console.log("save()...");
const postData = new FormData(document.getElementById("login-from"));
axios
.post("/api/login/", postData)
.then((res) => {
console.log("LOGIN POST RES", res);
// alert(`user ${res.data.username} login OK`);
this.dialogClose.success = true;
this.this.me = res.data;
})
.catch((err) => {
console.log("LOGIN POST ERR.RESPONSE", err.response);
this.dialogClose.fail = true;
// alert("login FAIL");
});
},
},
};
</script>
// LoginDialog.vue
<template>
<div>
<!-- 로그인 dialog -->
<v-dialog v-model="dialogOpen" max-width="500">
<v-card width="800" class="mx-auto mt-5">
<v-toolbar color="primary" dark flat>
<v-toolbar-title class="pb-0">
<h2>Login</h2>
</v-toolbar-title>
</v-toolbar>
<v-card-text>
<v-form id="login-from" ref="loginForm">
<v-text-field
label="Username"
name="username"
prepend-icon="mdi-account-circle"
></v-text-field>
<v-text-field
:type="showPassword ? 'text' : 'password'"
label="Password"
name="password"
prepend-icon="mdi-lock"
:append-icon="showPassword ? 'mdi-eye' : 'mdi-eye-off'"
#click:append="showPassword = !showPassword"
autocomplete="on"
></v-text-field>
</v-form>
</v-card-text>
<v-divider></v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
text
color="grey"
center
#click="(dialogOpen = false), $refs.loginForm.reset()"
>Cancel</v-btn
>
<v-btn color="success" center #click="dialogOpen = false"
>Register</v-btn
>
<v-btn color="info" center #click="save()">Login</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- login success 팝업창 -->
<v-dialog v-model="dialogClose.success" max-width="290">
<v-card>
<v-card-title class="text-h5"> Login Success! </v-card-title>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="green darken-1"
text
#click="dialogClose.success = false"
>
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- login fail 팝업창 -->
<v-dialog v-model="dialogClose.fail" max-width="290">
<v-card>
<v-card-title class="text-h5"> Login Fail! </v-card-title>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="green darken-1" text #click="dialogClose.fail = false">
Close
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
So the Axios call goes well, but after that, in the .then block an error is thrown and caught by the .catch block. This is also why the err.response is empty, because that is an error object of Axios. If you log the err instead of err.response you might see the actual error (as Akzhol Kadylbek suggested in his comment).
Looking at your code, I presume that error comes from this line:
this.this.me = res.data;
/// change to this.me = res.data;
The double this. looks like a typo.
Hope this helps.

Vuetify reset form after submitting

I am using a form inside dialog using vuetify.
Imported the component in page like this -
<template>
<div>
<topicForm :dataRow="dataRow" v-model="dialog" />
</div>
</template>
methods: {
openDialog(item = {}) {
this.dataRow = item;
this.dialog = true;
},
}
Dialog form code -->
<template>
<div>
<v-dialog v-model="value" max-width="500px" #click:outside="close">
<v-card outlined class="pt-5">
<v-form ref="form" class="px-3">
<v-card-text class="pt-5">
<v-row no-gutters>
<v-text-field
required
outlined
label=" Name"
v-model="data.name"
:rules="[rules.required]"
></v-text-field>
</v-row>
<v-row no-gutters>
<v-textarea
required
outlined
label=" Description"
v-model="data.description"
></v-textarea>
</v-row>
</v-card-text>
</v-form>
<v-divider> </v-divider>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
large
dark
outlined
color="success"
#click="save"
class="ma-3"
>
Save
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
</template>
props: [
"dataRow",
"value",
// ----------------------
],
methods: {
save() {
if (this.$refs.form.validate()) {
this.$root
.$confirm("Are you sure you want to save?")
.then((confirm) => {
if (confirm) {
this.ADD_TOPIC_DATA(this.data)
.then((data) => {
this.FETCH_TOPIC_DATA();
this.$refs.form.reset();
this.$refs.form.resetValidation();
this.close();
})
.catch((err) => {
console.log(err)
});
}
});
}
},
close() {
this.$emit("input", false);
},
}
watch: {
dataRow(val) {
this.data = { ...val };
},
},
Problem I am having is after adding a data, then if I try to add again by opening the dialog, the required field shows validation error, which is name here!
Image of that -->
Searched in stackoverflow. Found that should use this.$refs.form.reset(). Used that in save method without success. Also used this.$refs.form.resetValidation(), but don't work.
Any suggestion?
Thanks in advance.
The problem here is you're assigning new value to dataRow when opening the dialog which triggers validation inside the dialog. You could also use lazy-validation prop which allows you to only manually trigger the validation.

How to show an icon only when certain tab is selected?

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>

Vue, error [vuex] do not mutate vuex store state outside mutation handlers

Here is original code. Very simple, sign in form. We have Email field, password. It takes this parameters and on clicking submit button it checks the user and writes his user.uid into Vuex. But I'm getting error which is listed above in title. I did research and it looks like it's a common issue in Vuex, due to those fields at some point updating Vuex store 'on a fly' which is false in my case, cause it only updates Vuex store when you press a submit button. Anyhow decided corrected to be look like this and still have no luck
original code
<template>
<div class="form__inner">
<div class="overlay" #click="$store.commit('logReg/logIn')"></div>
<v-container
fill-height
fluid>
<v-row
align="center"
justify="center">
<v-col cols="2">
<v-card>
<v-card-title>
Log in
</v-card-title>
<v-card-text>
<v-text-field placeholder="Email"
v-model="logIn"/>
<v-text-field placeholder="Password"
v-model="password"/>
</v-card-text>
<v-card-actions>
<v-btn color="success"
class="mx-auto"
#click="signIn">Log me in</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</div>
</template>
<script>
export default {
data(){
return {
logIn: '',
password: ''
}
},
methods: {
async signIn(){
let res = await this.$fireAuth.signInWithEmailAndPassword(this.logIn, this.password);
this.$store.commit('userState', res);
}
}
}
</script>
my vuex
export const state = () => ({
user: null
})
export const mutations = {
userState(state, authUser){
state.user = authUser;
}
}
my try to fix issue which still had no luck, gives same error
<template>
<div class="form__inner">
<div class="overlay" #click="$store.commit('logReg/logIn')"></div>
<v-container
fill-height
fluid>
<v-row
align="center"
justify="center">
<v-col cols="2">
<v-card>
<v-card-title>
Log in
</v-card-title>
<v-card-text>
<v-text-field placeholder="Email"
v-model="logIn"/>
<v-text-field placeholder="Password"
v-model="password"/>
</v-card-text>
<v-card-actions>
<v-btn color="success"
class="mx-auto"
#click="signIn">Log me in</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
</v-container>
</div>
</template>
<script>
export default {
data(){
return {
logIn: '',
password: ''
}
},
computed: {
logg: {
get(){
return this.logIn;
},
set(val){
this.logIn = val;
}
},
pass: {
get(){
return this.password;
},
set(val){
this.password = val;
}
}
},
methods: {
async signIn(){
let res = await this.$fireAuth.signInWithEmailAndPassword(this.logg, this.pass);
this.$store.commit('userState', res);
}
}
}
</script>
You have to use mutations like this:
<script>
import {mapMutations} from 'vuex';
export default {
data(){
return {
logIn: '',
password: ''
}
},
methods: {
...mapMutations({
userState: 'userState'
}),
async signIn(){
let res = await this.$fireAuth.signInWithEmailAndPassword(this.logIn,this.password);
this.userState(res);
}
}
}
</script>