Can't validate v-text-field [migrating from older version of Vuetify] - javascript

I've been migrating an old project from last year since Entity Framework 5 was released. Since I'm also migrating the frontend from the previous version of Vuetify I worked with last year (from 2.2.11 to 2.4.0), I've encountered some issues that I've had to look up online and fix, but I got this sudden issue that I can't quite lay a finger on and haven't been able to find a similar issue with an answer.
I'm trying to validate a v-text-field inside a v-card to not save a record if the v-text-field length is less than 3 or greater than 50 characters. Despite that I've followed up the same code I used last year to validate my v-text-field, I get the following errors on chrome console:
The last 2 errors from this image pop up when you click save when it should show the validation message:
The code used in the component is the following.
For the Validation message that should pop below the description v-text-field in red:
VUE:
<template v-slot:top>
<v-toolbar flat>
<v-dialog v-model="dialog" max-width="500px">
<template v-slot:activator="{ on, attrs }">
<v-btn color="primary" dark class="mb-2" v-bind="attrs" v-on="on">New</v-btn>
</template>
<v-card>
<v-container>
<v-row>
<v-col cols="12" sm="12" md="12">
<v-text-field v-model="name" label="Name"></v-text-field>
</v-col>
<v-col cols="12" sm="12" md="12">
<v-text-field v-model="description" label="Description"></v-text-field>
</v-col>
<v-col cols="12" sm="12" md="12" v-show="valida">
<div class="red--text" v-for="v in validaMessage" :key="v" v-text="v">
</div>
</v-col>
</v-row>
</v-container>
</v-card>
</v-dialog>
</v-toolbar>
</template>
JAVASCRIPT:
<script>
import axios from 'axios'
export default {
data(){
return {
categories:[],
dialog: false,
dialogDelete: false,
headers: [
{ text: 'Options', value: 'actions', sortable: false, class:"primary--text" },
{ text: 'Name', value: 'name', class:"primary--text" },
{ text: 'Description', value: 'description', sortable: false, class:"primary--text" },
{ text: 'Status', value: 'status', sortable: false, class:"primary--text" },
],
search: '',
desserts: [],
editedIndex: -1,
editedItem: {
name: '',
calories: 0,
fat: 0,
carbs: 0,
protein: 0,
},
id: '',
name: '',
description: '',
valida: 0,
validaMessage:[]
}
},
methods: {
save () {
if (this.valida()){
return;
}
if (this.editedIndex > -1) {
//Code to update
}
else {
let me=this;
axios.post('api/Categories/Create',{
'name': me.name,
'description': me.description
}).then(function(response){
me.close();
me.list();
me.clean();
}).catch(function(error){
console.log(error);
});
}
},
valida(){
this.valida=0;
this.validaMessage=[];
if (this.name.length < 3 || this.name.length > 50){
this.validaMessage.push("The name must have between 3 and 50 characters.")
}
if (this.validaMessage.length){
this.valida=1;
}
return this.valida;
}
},
}
</script>
This is how it used to show like in my older version of the project:
I don't know if something that was changed in the Vuetify update version from 2.2.11 to 2.4.0 is interfering with the ability to implement this method inside the component to be able to show or hide the validation message. I'm trying to resolve this to avoid having to recur to 3rd party validation services like vee-validate or vuelidate. What could it be? Thank you for taking your time in reading this!

To sum up, these were the reasons for the errors:
There were a data property and a method with the same name - valida
v-btn component had a deleted method initialize provided to #click event.
And another tip as a bonus:
You have a v-col that spans to 12 columns: <v-col cols="12" sm="12" md="12">. Since it should span 12 columns on every screen size, there's really no need to define the columns span for small and medium breakpoints. So in this case it really should be only <v-col cols="12"> - will save you a little file size and loading time.

Related

Vuetify Dynamic Binding of Property

I've got a form which contains a dynamic set of input components (v-selects and v-text-fields) that a user has to set. However, I'm really struggling to understand how to retrieve the values from these input components once the user submits the form. My input setup looks like this:
<v-row>
<v-col
v-for="(item, index) in documentTags.tags"
:key="index"
cols="18"
sm="8"
md="6"
>
<v-select
v-if="item.InputType === 'Combobox'"
:v-model="documentTagResponses[index]"
:name="item.Name"
:items="item.TagValueOptions"
:rules="rules.ComboboxRule"
item-text="Value"
:label="item.Name"
required
>
</v-select>
<v-text-field
v-else-if="item.InputType === 'Textbox'"
:v-model="documentTagResponses[index]"
:name="item.Name"
:label="item.Name"
:rules="rules.TextboxRule"
required
>
</v-text-field>
</v-col>
</v-row>
And my documentTags definition looks something like this:
{
tags: [
{
TagDefinitionId: '1',
InputType: 'Combobox',
Name: 'Name_1',
TagValueOptions: [
{
Value: 'Option 1',
},
{
Value: 'Option 2',
},
{
Value: 'Option 3',
},
],
},
{
TagDefinitionId: '2',
InputType: 'Textbox',
Name: 'Name_2',
TagValueOptions: [],
},
],
}
I'm trying to bind the form responses from these inputs to an array called documentTagResponses.
So, something like this:
export default {
name: 'MyModal',
data: () => ({
documentTagResponses: [],
}),
methods: {
validate() {
const valid = this.$refs.form.validate();
if (valid) {
for (const key of Object.keys(this.documentTagResponses)) {
console.log(`${key} -> ${this.documentTagResponses[key]}`);
}
}
},
};
Then, when the user clicks the submit button, I call the validate function to ensure the components are valid and then do something with the values... Right now I'm simply trying to print the values of each component to the console. However, my documentTagResponses array is always empty. Does anyone know why I can't seem to access the values that are being set in these components?
I just tested your code in my project and the problem was :v-model
We don't need : in v-model
So the code can be like below
<v-row>
<v-col
v-for="(item, index) in documentTags.tags"
:key="index"
cols="18"
sm="8"
md="6"
>
<v-select
v-if="item.InputType === 'Combobox'"
v-model="documentTagResponses[index]"
:name="item.Name"
:items="item.TagValueOptions"
:rules="rules.ComboboxRule"
item-text="Value"
:label="item.Name"
required
>
</v-select>
<v-text-field
v-else-if="item.InputType === 'Textbox'"
v-model="documentTagResponses[index]"
:name="item.Name"
:label="item.Name"
:rules="rules.TextboxRule"
required
>
</v-text-field>
</v-col>
</v-row>

How to submit form to array and clear inputs in vue

I have a vue form inside a dialog. Where the user can select a date and multplie starting times and ending times. So far I can save one object consisting of one date and multiple times. But when I want to add another object it takes the new date but changes the time values for every object.
for example if I add first an object with 05.09.2021 start:15:00 end: 16:00 and then add another object with date: 06.09.2021 start: 16:00 end: 17:00. The start and end is changed to the latest value of all objects, but I want each of them to be individually. I tried submitting a form, but sadly I could not make it work because it is reloading the page which I do not want, if i use .prevent on submit my error with time changing for every object still consists. Could someone take a look at my code and point me my mistake out`?
HTML:
<v-row>
<v-col cols="12" sm="12">
<v-menu
ref="menu3"
v-model="menu3"
:close-on-content-click="false"
:return-value.sync="dates"
transition="scale-transition"
offset-y
min-width="auto"
>
<template v-slot:activator="{ on, attrs }" >
<v-text-field
v-model="dates"
label="Picker in menu"
prepend-icon="mdi-calendar"
readonly
v-bind="attrs"
v-on="on"
></v-text-field>
</template>
<v-date-picker
v-model="dates"
no-title
scrollable
>
<v-spacer/>
<v-btn
text
color="primary"
#click="menu3 = false"
>
Cancel
</v-btn>
<v-btn
text
color="primary"
#click="$refs.menu3.save(dates) "
v-on:click=" menu3 = false"
>
OK
</v-btn>
</v-date-picker>
</v-menu>
<v-btn v-on:click="addTimeFields()">Add Time</v-btn>
</v-col>
</v-row>
<v-row v-for="(find, index) in selectedTime" >
<v-col
cols="6"
sm="6">
<v-text-field
v-model="find.startTime"
label="Starttime"
type="time"
></v-text-field>
</v-col>
<v-col
cols="6"
sm="6">
<v-text-field
v-model="find.endTime"
label="Untiltime"
type="time"></v-text-field>
</v-col>
</v-row>
</form>
Javascript:
<script>
import MeetingsTableComponent from "#/components/MeetingsTableComponent";
import DatePickerComponent from "#/components/DatePickerComponent";
export default {
name: "NextMeetingCardComponent",
data: () => ({
selectedTime: [],
dates: new Date().toISOString().substr(0,10),
datesFinal: [],
dialog: false,
menu: false,
modal: false,
menu2: false,
menu3: false
}),
methods:{
addTimeFields(){
this.selectedTime.push({
startTime:"",
endTime: "",
})
},
saveDateAndTIme(e){
this.datesFinal.push({
date: this.dates,
times : [this.selectedTime]
}
)
this.$refs.form.submit()
},
clearArrays(){
while (this.selectedTime.length){
this.selectedTime.pop()
}
}
}
};
</script>
I tried clearing the selectedTimes array which is pushed to datesFinal after pushing it but then every value is deleted.
I think there's an error in saveDateAndTIme(): times contains a nested array of the this.selectedTime array, but that should be unnested (i.e., set times to this.selectedTime itself).
After pushing this.selectedTime into datesFinal, you could clear the form by setting this.selectedTime to an empty array.
export default {
methods: {
saveDateAndTIme(e) {
this.datesFinal.push({
date: this.dates,
times: this.selectedTime, 👈
})
this.selectedTime = [] 👈
},
}
}
demo

Vue push into nested array

I have a vue application where I am trying to save an array which consists of a date field and has another array inside with time and time has startTime and untilTime as values.
What i want to achieve is that that when I click on a button the fields connected to time.startTime and untilTime should be added on button click. But I am getting this error:
vue.runtime.esm.js?2b0e:619 [Vue warn]: Avoid using non-primitive value as key, use string/number value instead.
found in
---> <DatePickerComponent> at src/components/DatePickerComponent.vue
<VCard>
<VThemeProvider>
<VDialog>
<VsRow>
<VCard>
<NextMeetingCardComponent> at src/components/NextMeetingCardComponent.vue
<DashboardComponent> at src/views/DashboardComponent.vue
<VMain>
<VApp>
<App> at src/App.vue
<Root>
I am a bit new to vue and javascript could someone point out my error maybe?
<template>
<div>
<v-row>
<v-col cols="12" sm="12">
<v-menu v-for="item in dates" :key="item"
ref="menu"
v-model="menu"
:close-on-content-click="false"
:return-value.sync="dates"
transition="scale-transition"
offset-y
min-width="auto"
>
<template v-slot:activator="{ on, attrs }" >
<v-text-field
v-model="item.date"
label="Picker in menu"
prepend-icon="mdi-calendar"
readonly
v-bind="attrs"
v-on="on"
></v-text-field>
</template>
<v-date-picker
v-model="dates"
no-title
scrollable
>
<v-spacer/>
<v-btn
text
color="primary"
#click="menu = false"
>
Cancel
</v-btn>
<v-btn
text
color="primary"
#click="$refs.menu.save(dates)"
>
OK
</v-btn>
</v-date-picker>
</v-menu>
<v-btn v-on:click="addTimeFields()">Add Time</v-btn>
</v-col>
</v-row>
<v-row v-for="i in dates" :key="i">
<v-col
cols="6"
sm="6"
>
<v-text-field
v-model="i.time.startTime"
label="Starttime"
type="time"
></v-text-field>
</v-col>
<v-col
cols="6"
sm="6"
>
<v-text-field
v-model="i.time.untilTime"
label="Untiltime"
type="time"
></v-text-field>
</v-col>
</v-row>
</div>
</template>
<script>
export default {
name: "DatePickerComponent",
data: () => ({
dates: [{date: new Date().toISOString().substr(0,10), time: [{
startTime: "",
untilTime: ""
}]}],
timeInputFields:[],
selectedDate: [],
menu: false,
modal: false,
menu2: false,
}),
methods:{
addTimeFields(){
this.dates[0].time.push({
startTime: "",
untilTime: "",
})
}
}
};
</script>
Output Vue:
Vue output
I think there are a couple of issues.
time is not an array, it is an object
You don't have 2 dates in the array, so probably want the 0 based index.
#2 is where the error is coming from.
addTimeFields(){
this.dates[0].time.push({
startTime: "",
untilTime: "",
})
}
Since your first entry already has start and until times set, to update you just need to to:
this.dates[0].time = {
startTime: "",
untilTime: "",
}
or
this.dates[0].time.startTime = "",
this.dates[0].time.untilTime = "",
EDIT one
I created a code pen for your code, there are quite a few errors, probably around the setup, but this screenshot shows what happens if you add two dates into the array. You get a list of them at the top, and then a list of the times. This makes me think you probably are just wanting one?
Please see this pen, https://codepen.io/OblivionSY/pen/rNyOLpw?editors=1011 it is not amazing, and doesn't fully work (date picker has an error)
Some general notes though:
make sure your :key value are primitive (string, int etc) and unique
try and split up the functionality into components. If you have multiple dates, then have one component to deal with editing a single date and the respective times.
feel free to edit the pen if you want me to take another look.

Phone number with dropdown country code vue js not working?

I am following this link: https://codepen.io/otuzel/pen/PooBoQW?editors=1011
but giving error Unknown custom element: - did you register the component correctly?
i have installed plugin --> npm install vue-tel-input
<div id="app">
<v-app id="inspire">
<v-form>
<v-container>
<v-row>
<v-col cols="12" sm="6" md="3">
<vue-tel-input v-bind="bindProps" v-model="phone" v-on:country-changed="countryChanged"></vue-tel-input>
</v-col>
</v-row>
</v-container>
<v-btn
color="success"
#click="submit"
>
submit
</v-btn>
</v-form>
in script
<script>
export default {
data() {
return {
phone: null,
country: null,
bindProps: {
mode: "international",
placeholder: "Enter a phone number",
required: false,
enabledCountryCode: true,
enabledFlags: true,
autocomplete: "off",
name: "telephone",
maxLen: 25,
inputOptions: {
showDialCode: true
}
}
}
},
methods: {
countryChanged(country) {
this.country = '+' + country.dialCode
},
submit() {
console.log(this.phone)
console.log(this.country)
}
}
}
</script>
giving error Unknown custom element: - did you register the component correctly? Why it is happening?
i have installed plugin --> npm install vue-tel-input

How to hide all buttons except clicked one if they are listed in v-for?

I have projects route where I used v-cards to show project name, link to details and button that should start project. When I click button it is disabled and another is shown-to stop it. Problem is that to show all projects cards I used v-for that goes through all projects. When I click on one start button, all are disabled (and that's ok), but I want only one stop button to appear, not all. I can get project id but I can't wrap my head around how to disable all others projects stop buttons
<v-flex v-for="project in projects"
:key="project.id" xs4>
<v-card>
<v-card-title>
<span class="headline">{{ project.name }}</span>
<v-spacer></v-spacer>
<v-btn
v-if="!isButtonActive"
left
small
fab
outline
color="green"
v-model="isButtonActive"
#click="startStop(isButtonActive, project.id)">
<v-icon>play_arrow</v-icon>
</v-btn>
<v-btn
v-if="isButtonActive"
small
v-model="isButtonActive"
#click="startStop(isButtonActive, project.id)">
<stopwatch />
</v-btn>
</v-card-title>
<v-card-actions>
<v-btn
small
flat
#click="goTo({
name: 'project',
params: {
projectId: project.id
}
})">
Project details
</v-btn>
</v-card-actions>
</v-card>
</v-flex>
in script:
startStop (isButtonActive, projectId) {
console.log(projectId)
this.isButtonActive = !isButtonActive
// hideButtons(projectId)
}
I think you'll want to store all the data about your buttons in an array, here's a quick crack at what you may be looking to do.
I've edited the snippet to track the index and also track what project, and buttonType is active. The general concept is you need to track what project is 'activated', and you'll need a mechanism to change what project is active.
data () {
return {
activeProject: 0,
activeButton: 'start',
projects: [
{
name: 'one',
active: true
},
{
name: 'two,
active: false
}
],
buttons: [
{
color: 'green',
active: true,
icon: 'play_arrow',
type: 'start'
},
{
color: 'blue',
active: false,
type: 'stop'
}
]
}
},
methods: {
startStop (projectId) {
this.buttons.forEach((button) => {
if (button.type !== activeButton) {
button.active = true
} else {
button.active = false
}
})
},
activateProject (index) {
this.activeProject = index
}
}
<v-flex v-for="(project, index) in projects"
:key="project.id" xs4>
<v-card>
<v-card-title>
<span class="headline">{{ project.name }}</span>
<v-spacer></v-spacer>
<v-btn v-for="button in buttons"
v-if="button.active && activeProject === index"
:color="button.color"
v-model="button.active"
#click="startStop()">
<v-icon v-if="button.type === 'start'">play_arrow</v-icon>
<stopwatch v-else />
</v-btn>
</v-card-title>

Categories