I am building a Vue app. I have two components that are related to each other. One of them is called loginRegister.vue
and the code of that is here:
loginRegister.vue:
<template>
<BaseModal idBtn = "regis" btnOneText="Cancel" :btnTwoText="button2Text['register']" v-show="showModal1" @close="showModal1 = false" @submitForm="registerUser(regLogPara['register'])" :popoverVue = "showToolTip.register">
<!-- the material that must be shown in modal comes here. it is better to use bootstrap "card" classes for compatible design -->
<!-- ################ -->
<!-- transition part -->
<!-- ################ -->
<transition name="fade">
<div v-if="modalAlert==='form'" key="item1">
<h4 class="card-title text-center my-3">Create Your Account</h4>
</div>
<!-- showing success message -->
<div v-else-if="modalAlert==='success'" key="item2">
<p>you succeed</p>
</div>
<!-- showing error message -->
<div v-else key="item3">
<p>there is an error!</p>
</div>
</transition>
</BaseModal>
</template>
<script>
import BaseButton from './BaseButton.vue';
import BaseInput from './BaseInput.vue'
import BaseModal from './BaseModal.vue';
import { onMounted, reactive, ref } from 'vue';
export default {
name: "loginRegister",
components: {
BaseModal,
BaseButton,
BaseInput
},
setup(props) {
const showModal = ref(false);
const showModal1 = ref(false);
const modalAlert = ref("form");
const registerUser = async (checkPara) => {
/* This function is responsible for sending form data to backend and getting the result from backend */
if (checkPara == "reset") {
/* for showing form again if there is a back-end error */
console.log("reset form");
modalAlert.value = "form";
button2Text["login"] = "Submit";
button2Text["register"] = "Submit";
regLogPara["login"] = "login";
regLogPara["register"] = "register";
} else {
/* for submiting form */
modalAlert.value = "error";
button2Text[checkPara] = "Try again";
regLogPara[checkPara] = "reset";
console.log("register function");
}
}
return {
registerUser,
showModal,
showModal1,
validation,
blurInput,
loginValid,
registerValid,
finalCheck,
showToolTip,
store,
modalAlert,
button2Text,
regLogPara
}
}
};
</script>
The other one called BaseModal.vue
and the code of that is here:
BaseModal.vue:
<template>
<div class="modal-overlay container-fluid p-0">
<div class="row align-items-center justify-content-center" @click.self="$emit('close')">
<div class="col-md-6">
<div class="card">
<div class="card-body">
<!-- text and other html comes here in the slot -->
<!-- ############## -->
<!-- this is the slot part -->
<!-- ############## -->
<slot></slot>
<div class="card-footer d-flex justify-content-around align-items-center">
<base-button
large
v-if="btnOneText"
kind = "btn-secondary"
:textBtn = "btnOneText"
@click="$emit('close')"
>
</base-button>
<base-button
large
v-if="btnTwoText"
kind = "btn-secondary"
:textBtn = "btnTwoText"
@click="popoverFunc"
@blur="popoverDisable"
:id="idBtn"
>
</base-button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import BaseButton from './BaseButton.vue';
import bootstrap from "bootstrap/dist/js/bootstrap.bundle.min.js";
export default {
// $emit('submitForm'),
name: "BaseModal",
props: {
btnOneText: {
type: String
},
btnTwoText: {
type: String
},
popoverVue: {
type: Boolean
},
idBtn: {
type: String
}
},
computed: {
popOverData: function () {
return this.popoverVue;
},
popVar: function() {
return new bootstrap.Popover(document.getElementById(this.idBtn), {
trigger: "manual",
title: "Notice:",
content: "Please fill all fields in the correct way to submit your information!",
customClass: "myPopover",
placement: "top"
})
}
},
data() {
return {
showPopOver: false
}
},
emits: ["close", "submitForm"],
components: {
BaseButton
},
watch: {
popOverData: function (newState, oldState) {
if(newState === true) {
this.showPopOver = true;
this.popoverFinal();
} else {
this.showPopOver = false;
this.popoverFinal();
}
}
},
methods: {
popoverFunc: function() {
this.$emit('submitForm');
if (this.popOverData) {
this.showPopOver = true;
this.popoverFinal();
}
},
popoverDisable: function() {
console.log("popoverDisable");
this.showPopOver = false;
this.popoverFinal();
},
popoverFinal: function() {
console.log(this.showPopOver);
/* this function is responsible for showing and hiding the popover according to "showPopOver" data */
if (this.showPopOver) {
this.popVar.show();
} else {
this.popVar.hide();
}
}
}
};
</script>
<style scoped src="../assets/css/compoStyles/baseModal.css"></style>
There are some codes that are not related to this question and also I tried to simplify the codes and clarify the parts that are related to transition
and slot
in my components code.
Although the codes may seem long or complicated, the goal that I want to reach is simple. I want to submit a register form in a modal component. Actually the user in my app clicks on register button and then the BaseModal.vue
component is shown. In that case the register form (that for simplicity I substitute that with a h4
tag) is the default thing that user could see. After submitting the form according that the process is successful or there is an error, I want to show a message to the user and change the text of button from submit to try again if there is an error. After that when the user clicks try again
button the form (h4
tag) must be fade in again. So I tried the v-if/v-else-if/v-else
structure of Vue in my loginRegister.vue
component. The code that I used in transition part
is similar to the code that Vue documentation is used, But the transition does not work correctly. In my local development environment, the h4
tag disappears smoothly and then no message is shown, after clicking try again
the h4
tag fade in again. Also in the console I could see this warning:
[Vue warn]: <transition> can only be used on a single element or component. Use <transition-group> for lists.
at <BaseTransition mode=undefined appear=false persisted=false ... >
at <Transition name="fade" >
at <BaseModal idBtn="regis" btnOneText="Cancel" btnTwoText="Try again" ... >
at <LoginRegister>
at <App>
But I don't think that is related to my issue, because I did not use transition on multi elements in my app. So could anyone please help me that what is wrong in my codes?
It seems like you want baseModal.vue to be inside loginRegister.vue and the baseModal to have some kind of transition whenever some state changes? Try changing
<transition></transition>
into<transition-group></transition-group>