vue-i18n translation for validation error working only after form reset in vuetify form - vue.js

I'm using form validation in application, I want my validation error message to be translated. It is getting translated only after reset form.
I have tried translation in computed property, and it's working when I do
computed as below, but error message is not disappearing after touched:
{
return [this.$t('LANGUAGE')]
}
In App Component
<template>
<div id="app">
<grid_Component/>
<div class="locale-changer" style="background: black">
<select v-model="$i18n.locale">
<option v-for="(lang, i) in lang" :key="`Lang${i}`" :value="lang">{{
lang }}
</option>
</select>
</div>
</div>
</template>
<script>
import form_Component from './components/form_Component.vue'
import form_Component from './components/form_Component.vue'
import i18n from './i18n'
export default {
data () {
return{
lang: ['GB', 'NO']
}
},
name: 'app',
components: {
form_Component,
},
}
</script>
GB.json file
{
"LANGUAGE": "English"
}
NO.json file
{
"LANGUAGE": "Norwegian"
}
form component
<template>
<v-form ref="form" v-model="valid" lazy-validation>
<v-text-field v-model="name" :counter="10" :rules="nameRules"
label="Name" required>
</v-text-field>
<v-btn :disabled="!valid" color="success" #click="validate">
Validate
</v-btn>
<v-btn color="error" #click="reset">
Reset Form
</v-btn>
<v-btn color="warning" #click="resetValidation">
Reset Validation
</v-btn>
</v-form>
</template>
<script>
export default {
data: () => ({
valid: true,
name: '',
}),
methods: {
validate () {
if (this.$refs.form.validate()) {
this.snackbar = true
}
},
reset () {
this.$refs.form.reset()
},
resetValidation () {
this.$refs.form.resetValidation()
}
},
computed: {
nameRules(){
return [v => !!v || this.$t('LANGUAGE')]
}
}
}
</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>

Is there any way to pass props to component without calling it

I have 3 components like: Parent, First-child and Second-child. And I am iterating First-child in Parent component in array(it is cards), and I want to call Second-child in Parent component with First-child's props(props of one card).
My Parent component looks like this(how I am calling First-child):
``
<CardComponent
v-for="card of cards"
:key="card.urlsId"
:cardImages="card.images"
:cardTitle="card.title"
:cardDescription="card.description"
:mediaRef="card.urlsId"
:dbRef="card.dbId"
:deleteBtn="true"
:imagesWithSlider="true"
/>
And my First child is:
<template>
<div class="cards">
<v-card class="card-container">
<div class="delete-btn">
<v-btn
v-if="deleteBtn"
class="mx-2"
fab
dark
small
#click="$emit('onOpenDeleteModal')"
>
<v-icon dark> mdi-delete </v-icon>
</v-btn>
</div>
<ImageSlider
v-if="imagesWithSlider"
:imagesArray="cardImages"
:arrowBtns="false"
/>
<div class="text-container">
<h3 class="card-title">{{ cardTitle }}</h3>
<p class="card-description">{{ cardDescription }}</p>
</div>
</v-card>
</div>
</template>
<script>
export default {
props: {
cardImages: {
type: Array,
default: null,
},
cardTitle: {
type: String,
default: 'Title',
},
cardDescription: {
type: String,
default: 'Description',
},
deleteBtn: {
type: Boolean,
},
imagesWithSlider: {
type: Boolean,
},
mediaRef: {
type: String,
default: '',
},
dbRef: {
type: String,
default: '',
},
deleteModalOpen: {
type: Boolean,
},
},
emits: ['onOpenDeleteModal', 'onCloseDeleteModal'],
}
</script>
And my Second-child is:
<template>
<v-card class="modal" :loading="newCard.loading ? true : false">
<v-card class="modal-header">
<h3 v-if="addCardModal" class="header-title">New card</h3>
<h3 v-if="deleteModal" class="header-title">Delete</h3>
<v-icon aria-hidden="false" width="100%" #click="$emit('closeModal')"
>mdi-close</v-icon
>
</v-card>
<!-- Delete Modal -->
<div v-if="deleteModal" class="modal-delete">
<h3>Are you really want to delete this card ?</h3>
<div class="modal-delete-btns">
<v-btn #click="$emit('closeModal')">Cancel</v-btn>
<v-btn color="error" #click="$emit('onDeleteCard')">Delete</v-btn>
</div>
</div>
<!-- Add New Card Modal -->
<form
v-if="addCardModal"
class="modal-container"
#submit.prevent="postNewCardToDb"
>
<v-file-input
v-model="newCard.cardImages"
:clearable="false"
multiple
show-size
label="Upload card images"
#change="previewImage"
>
</v-file-input>
<v-file-input
v-model="newCard.cardVideo"
:clearable="false"
show-size
label="Upload video"
>
</v-file-input>
<div v-if="newCard.cardImageUrls.length !== 0" class="preview-image">
<ImageSlider :imagesArray="newCard.cardImageUrls" :arrowBtns="true" />
</div>
<v-text-field
v-model="newCard.cardTitle"
label="Enter card title"
></v-text-field>
<v-text-field
v-model="newCard.cardSnippet"
label="Enter card description"
></v-text-field>
<v-btn type="submit" :loading="newCard.loading ? true : false" block
>POST</v-btn
>
</form>
</v-card>
</template>
<script>
import { v4 as uuidV4, v1 as uuidV1 } from 'uuid'
export default {
/* eslint-disable no-console */
props: {
addCardModal: {
type: Boolean,
},
deleteModal: {
type: Boolean,
},
},
emits: ['closeModal', 'onDeleteCard'],
data() {
return {
newCard: {
loading: false,
cardImages: [],
cardVideo: null,
cardImageUrls: [],
cardTitle: '',
cardSnippet: '',
},
}
},
methods: {
previewImage($event) {
for (const image of event.target.files) {
this.newCard.cardImageUrls.push(URL.createObjectURL(image))
}
},
async getMediaUrlsFromStorage(newCardData) {
const cardMediaRef = uuidV1()
const cardImagesRef = await this.$fire.storage
.ref('/albums_cards/')
.child(cardMediaRef)
const videoRef = await cardImagesRef.child(uuidV4())
if (this.newCard.cardVideo) {
await videoRef.put(this.newCard.cardVideo)
const videoUrl = await videoRef.getDownloadURL()
newCardData.video = videoUrl
}
newCardData.urlsId = cardMediaRef
const promiseArr = this.newCard.cardImages.map(async (image) => {
const imageRef = cardImagesRef.child(uuidV4())
await imageRef.put(image)
const imageUrl = await imageRef.getDownloadURL()
newCardData.images.push(imageUrl)
})
await Promise.all(promiseArr)
},
async postNewCardToDb() {
this.newCard.loading = true
const newCardData = {
urlsId: '',
title: this.newCard.cardTitle,
description: this.newCard.cardSnippet,
video: '',
images: [],
}
await this.getMediaUrlsFromStorage(newCardData)
await this.$fire.database.ref('albums/cards').push(newCardData)
console.log(newCardData)
this.newCard.loading = false
this.newCard.cardTitle = null
this.newCard.cardSnippet = null
this.newCard.cardImages = []
this.newCard.cardImageUrls = []
this.newCard.cardVideo = null
},
},
}
</script>
First-child is a card component and I need to pass props of each card to Second-child without calling it. I cant call Second-child in First-child because of iteration.
I hope I expleined it well

Vue vuetify Dialog How to tigger dialog component without click

How can I tigger the dialog from main file? I have no idea how to tigg ConfirmationDialog value "dislog" to true. Or any other method to do it? Dont want to group the code as a one file.
That is a component called ConfirmationDialog.vue
<template>
<v-layout row justify-center>
<v-btn color="primary" dark #click.native.stop="dialog = true">Open Dialog</v-btn>
<v-dialog v-model="dialog" max-width="290">
<v-card>
<v-card-title class="headline">Use Google's location service?</v-card-title>
<v-card-text>Let Google help apps determine location. This means sending anonymous location data to Google, even when no apps are running.</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="green darken-1"
flat="flat"
#click.native="dialog = false"
>Disagree</v-btn>
<v-btn color="green darken-1" flat="flat" #click.native="dialog = false">Agree</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-layout>
</template>
<script>
export default {
data() {
return {
dialog: false
}
}
}
</script>
Main File:
<template>
<div class="row">
<div class="col-12">
<confirmationDialog></confirmationDialog>
</div>
</div>
</template>
<script>
import confirmationDialog from '../confirmationDialog'
export default {
data() {
return {}
},
components: {
confirmationDialog
},
methods: {
update() {
// Todo: Tigger Confirmation Dislog
}
},
}
</script>
Add a prop called show to the child component (confirmationDialog ) and bind to a parent property :
confirmationDialog
...
<script>
export default {
props:['show'],
data() {
return {
dialog: false
}
},
mounted(){
this.dialog=this.show;
}
}
</script>
Main
<template>
<div class="row">
<div class="col-12">
<confirmationDialog :show="showDialog"></confirmationDialog>
</div>
</div>
</template>
<script>
import confirmationDialog from '../confirmationDialog'
export default {
data() {
return {
showDialog:false,
}
},
components: {
confirmationDialog
},
methods: {
update() {
this.showDialog=true;
}
},
}
</script>

Vue Passing Data from component to another component

I am making a "create account" flow for user and I am not able to pass data from one component to another. The first component has radio buttons with options of "tenant", "landlord", "contractor". Once the user selects "tenant", then the data should pass to the next step where they fill out a form with name and all that good stuff.. once they submit, it should all go together to the back end.
acc-for.vue with radio buttons component below.
<template>
<div>
<v-app
style="background-image: url('https://blog.modsy.com/wp-content/uploads/2019/06/D2_Full.jpg')"
>
<v-container class="pa-12">
<v-row>
<v-card class="pa-16">
<v-card-title>
Are you a?
</v-card-title>
<v-radio-group v-model="selectedValue" #change="selectedAcc">
<v-radio
v-for="account in accountType"
:key="account.name"
:value="account.name"
:label="account.name"
></v-radio>
</v-radio-group>
<v-row>
<v-btn rounded color="black" class="white--text" href="/login"
>Back</v-btn
>
<v-btn
rounded
color="black"
class="white--text"
#click="selected(accountSelected)"
>Next</v-btn
>
<!-- href="/create-acc" -->
</v-row>
</v-card>
</v-row>
</v-container>
</v-app>
</div>
</template>
<script>
import { mapMutations } from "vuex";
export default {
data() {
return {
selectedValue: false,
};
},
computed: {
accountType() {
return this.$store.state.accountType;
},
selected() {
return this.$store.state.selectedAccType;
},
},
methods: {
...mapMutations(["SELECTED_ACCOUNT_TYPE"]),
selectedAcc(e) {
this.$emit("selected-accountType", e);
},
},
};
</script>
<style></style>
createAccount.vue this component has the form for the fName and lName and all that good stuff..
<template>
<div>
<v-app
style="background-image: url('https://blog.modsy.com/wp-content/uploads/2019/06/D2_Full.jpg')"
>
<v-container class="pa-12">
<v-row>
<v-card class="pa-16">
<v-card-title>
{{ selectedTypeUser }}
</v-card-title>
<v-form>
<v-text-field
class="pa-4"
type="text"
v-model="newUser_fName"
label="First Name"
/>
<v-text-field
class="pa-4"
type="text"
v-model="newUser_lName"
label="Last Name"
/>
<v-text-field
class="pa-4"
type="text"
v-model="newUser_email"
label="Email"
/>
<v-text-field
class="pa-4"
type="text"
v-model="newUser_password"
label="Password"
/>
<v-row>
<v-btn rounded color="black" class="white--text" href="/acc-for"
>Back</v-btn
>
<v-btn
#click="registerUser"
rounded
color="black"
class="white--text"
>Next</v-btn
>
</v-row>
</v-form>
</v-card>
</v-row>
</v-container>
</v-app>
</div>
</template>
<script>
import { mapMutations } from "vuex";
import axios from "axios";
export default {
data() {
return {
newUser_fName: "",
newUser_lName: "",
newUser_email: "",
newUser_password: "",
};
},
methods: {
...mapMutations(["ADD_USER"]),
registerUser() {
let config = {
headers: {
"Content-Type": "application/json",
},
};
axios
.post(
"http://localhost:7876/createUser",
{
fName: this.newUser_fName,
lName: this.newUser_lName,
email: this.newUser_email,
password: this.newUser_email,
},
config
)
.then((response) => {
console.log(response.statusText);
})
.catch((e) => {
console.log("Error: ", e.response.data);
});
},
},
};
</script>
store.js (state) is below
// import vue from "vue";
import vuex from "vuex";
import axios from "axios";
import Vue from "vue";
Vue.use(vuex, axios);
export default new vuex.Store({
state: {
users: [],
accountType: [
{ name: "Tenant" },
{ name: "Landlord" },
{ name: "Contractor" }
],
selectedAccType: [],
},
mutations: {
ADD_USER: (state, payload) => {
state.users.push(payload.user);
},
SELECTED_ACCOUNT_TYPE: (state, payload) => {
state.selectedAccType.push(payload)
}
},
actions: {
addUser: ({ commit }, payload) => {
commit("ADD_USER", payload);
},
selectAcc: ({ commit }, payload) => {
commit("SELECTED_ACCOUNT_TYPE", payload)
}
},
// getters: {
// addAccountType(state, e) {
// state.accountType.push(e)
// },
// },
});
I see this on the button:
<v-btn rounded
color="black"
class="white--text"
#click="selected(accountSelected)"
>Next</v-btn
>
But I'm not finding a method with that name in your attached code. Double check that your names are all matched up and that you are calling the correct function on the click event.

Vuejs - Same component with different data

I am trying to re-use the same component, but load the components with different data. I thought simply providing unique id's would do the trick, but no luck. I switched from a Vuex store for this data, to using a dataShare This is what I'm doing:
The components:
<logoHeader :panel=0 title="Add your logo / header" id="top" topPadding="pt-10" />
<logoHeader :panel=1 title="Add your main image" id="main" topPadding="pt-0"/>
So its the exact same component, with some different props and different ids
This is the logoHeader component:
<template>
<v-row
:class="topPadding"
align="center"
justify="center"
>
<v-col
align="center"
justify="center"
cols="12"
>
<v-hover v-slot:default="{ hover }">
<v-card
:elevation="hover ? 12 : 0"
class="mx-auto"
max-width="600"
>
<v-img
v-if="showImage"
:src="imageUrl"
max-width="600px"
class="pointer"
#click="panel = 0"
>
</v-img>
<v-icon
v-if="!showImage"
class="my_dark_purple_text"
size="100"
#click="sendToPanel"
>add_box</v-icon>
<p class="my_dark_purple_text">{{ title }}</p>
<p>URL {{ imageUrl }}</p>
<p>Show image? {{ showImage }}</p>
</v-card>
</v-hover>
</v-col>
</v-row>
</template>
<script>
import {mapGetters} from 'vuex';
import {mapActions} from 'vuex';
import {dataShare} from '../../../packs/fresh-credit.js';
export default {
props: ['panel', 'title', 'topPadding'],
data() {
return {
imageUrl: "",
showImage: false,
}
},
created() {
dataShare.$on('imageUrl', (data) => {
this.imageUrl = data;
});
dataShare.$on('showImage', (data) => {
this.showImage = data;
});
},
computed: {
...mapGetters('emailPanel', [
'returnPanel'
]),
},
methods: {
...mapActions('emailPanel', [
'updatePanel'
]),
sendToPanel() {
this.updatePanel(this.panel);
},
},
}
</script>
And then finally this is where the data enters the system:
<template>
<v-expansion-panel-content>
<h1 class="subtitle-1 font-weight-bold">Only images files accepted</h1>
<v-file-input
v-model="image"
accept="image/*"
label="Image Upload"
prepend-icon="add_a_photo"
color='#68007d'
></v-file-input>
<v-btn
:disabled="disableUpload"
color="#68007d"
class="white--text"
#click="sendImage"
>Submit</v-btn>
</v-expansion-panel-content>
</template>
<script>
import axios from 'axios';
import {dataShare} from '../../../../packs/fresh-credit.js';
export default {
data() {
return {
image: null,
disableUpload: true,
}
},
watch: {
image: function() {
if(this.image.size > 0){
this.disableUpload = false;
}
else{
this.disableUpload = true;
}
}
},
computed: {
},
methods: {
sendImage() {
let formData = new FormData();
formData.append('file', this.image);
axios.post('/admin/features/images', formData,
{
headers: {
'Content-Type': 'multipart/form-data'
}
}
).then(response => {
dataShare.$emit('imageUrl', response.data);
dataShare.$emit('showImage', true);
});
}
},
}
</script>
Where did I go astray?
Add the key property to the components and set it to different values (for example 1 and 2). If the key has different values Vue will differentiate them when rendering. Here is a basic explanation.