I've got a couple fields:
<v-row>
<v-col cols="12" class="d-flex">
<v-text-field clearable outlined required :rules="rules.codeRules" name="code" v-model="attribute.code" label="Code"></v-text-field>
</v-col>
</v-row>
<v-row>
<v-col cols="12" class="d-flex">
<v-text-field clearable outlined required :rules="rules.nameRules" name="name" v-model="attribute.name" label="Name"></v-text-field>
</v-col>
</v-row>
In Vuetify's documents I see there's a couple properties named error which triggers an error state and error-messages with messages to be displayed.
When the form's submitted, if there's any errors on any of the fields I want to trigger these properties.
How can I do that? For instance, how can I manually set the field with the name of "code" into an error state by using the error property? how can I pass a personalized message to it? Do I need to specifically create a variable in the data() object in order to do what I wanna do? because if I have to do it that way it'd mean that I need to create an error and an error-messages properties in the data object for each and every field in my form!? or it can do by selecting exactly the field that I want to modify and somehow update its properties directly without the need of any variable from the model?
Thanks
Edit
Here's what I'm doing:
<v-row>
<v-col cols="12" class="d-flex">
<v-text-field clearable outlined required :error="formErrors.code.error" :error-message="formErrors.code.errorMessages" :rules="rules.codeRules" name="code" v-model="attribute.code" label="Code"></v-text-field>
</v-col>
</v-row>
My submit method is the following:
axios.post(postUrl, this.attribute, { Accept: "application/json" })
.then(response => {
if (response.data.success) {
Event.fire('message', {
type: 'success',
message: 'Attribute successfully saved'
});
this.$router.push('/attributes/list')
}
})
.catch(errors => {
// eslint-disable-next-line no-console
console.log(errors.response.data)
const responseErrors = errors.response.data
if (responseErrors) {
// eslint-disable-next-line no-console
console.log('here modafucka')
//const self = this
for (const key of Object.keys(responseErrors)) {
// eslint-disable-next-line no-console
console.log(responseErrors[key][0])
this.formErrors[key].error = true;
this.formErrors[key].errorMessages = responseErrors[key][0];
}
}
})
}
By setting this.formErrors[key].error = true; I'm able to put the field in an error state, but still the customized error message is not being displayed
First of all, you don't need both error and error-messages prop. If you just set error-messages, the input field will go in error state and the message will be shown
Do I need to specifically create a variable in the data() object in
order to do what I wanna do? because if I have to do it that way it'd
mean that I need to create an error and an error-messages properties
in the data object for each and every field in my form!
Yes, you'll need to set error-messages prop for each and every field. You already have separate variables for v-model and rules.
Ideally you would be running a for loop to generate the input fields(shown below), but a simple :error-messages="errorMessages.code" & :error-messages="errorMessages.name" will also work.
// Fields array
[
{
name: 'code',
rules: [ // list of rules ],
value: '' // Some value,
errorMessages: [] // Could be list or string
},
{
name: 'name',
rules: [ // list of rules ],
value: '' // Some value,
errorMessages: [] // Could be list or string
}
]
// Your form template
<v-row v-for="field in fields" :key="field.name">
<v-col cols="12" class="d-flex">
<v-text-field
clearable
outlined
required
:rules="field.rules"
:name="field.name"
v-model="field.value"
:label="field.name"
:error-messages="field.errorMessages"
>
</v-text-field>
</v-col>
</v-row>
Related
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>
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
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.
As the title states, Im looking to add a google autocomplete inside of a vuetify dialog box within vue.js. I have successfully added autocomplete to regular inputs on the page by using the mounted() function and attaching there(code below). However it seems that since the dialog box doesnt render until you click a button to launch it, using this.$refs and attaching an autocomplete to those inputs wont work. Ive also tried creating a function to attach after the dialog launches and it still does not work. Any insight appreciated.
The part that works:
mounted() {
console.log(this.$refs)
//creates google maps automcomplete on the address inputs. Gets the addresses and saves them as well as getting the lat and long from each and saving them
for (let ref in this.$refs) {
const options = {
componentRestrictions: { country: 'us' },
fields: ['geometry', 'name', 'formatted_address'],
strictBounds: false,
types: ['address'],
}
const autocomplete = new google.maps.places.Autocomplete(
this.$refs[ref],
options
)
autocomplete.addListener('place_changed', () => {
// selected place object, bring up info such as address & geo coords
const place = autocomplete.getPlace()
// gets the address and lat/long from the found address and saves them to be used later when actually creating the order
if (ref == 'pickupAddress') {
this.pickupAddress = `${place.formatted_address}`
this.pickupPair = place.geometry.location
} else {
this.dropoffAddress = `${place.formatted_address}`
this.dropoffPair = place.geometry.location
}
})
}
this.$store.dispatch('getOpenOrders')
}
The dialog box
<v-row justify="center">
<v-dialog v-model="dialog" persistent max-width="600px">
<template v-slot:activator="{ on, attrs }">
<v-btn
color="rgb(216, 52, 125)"
dark
v-bind="attrs"
v-on="on"
style="margin-top: 10px"
#click="addRefs"
>
Add a leg to an existing order
</v-btn>
</template>
<v-card>
<v-card-title>
<span class="headline">Add a leg</span>
</v-card-title>
<v-card-text>
<v-container>
<v-row>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Order ID*"
required
v-model="legId"
hint="Order ID of the order you want to add a leg to"
persistent-hint
></v-text-field>
</v-col>
<v-col cols="12" sm="6" md="4">
<v-text-field
label="Leg Letter (a-z)*"
required
v-model="legLetter"
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
label="Leg Pickup Address*"
ref="legPickupAddress"
required
v-model="legPickup"
></v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
label="Leg Dropoff Address*"
ref="legDropoffAddress"
required
v-model="legDropoff"
></v-text-field>
</v-col>
</v-row>
</v-container>
<small>*indicates required field</small>
<v-alert
class="v-alert"
v-if="noLegFoundAlert"
type="error"
dismissible
#click="noLegFoundAlert = !noLegFoundAlert"
>
No matching leg found, please enter another id or create a leg!
</v-alert>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn text #click="dialog = false"> Close </v-btn>
<v-btn text #click="addLeg"> Save </v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-row>
and finally the addRefs function which DOES NOT WORK
async addRefs() {
const options = {
componentRestrictions: { country: 'us' },
fields: ['geometry', 'name', 'formatted_address'],
strictBounds: false,
types: ['address'],
}
var input = this.$refs['legPickupAddres'] //DOES NOT WORK DOESNT EXIST APPARENTLY!!!!!!
const autocomplete1 = new google.maps.places.Autocomplete(input, options)
autocomplete1.addListener('place_changed', () => {
// selected place object, bring up info such as address & geo coords
const place = autocomplete.getPlace()
// gets the address and lat/long from the found address and saves them to be used later when actually creating the order
this.legPickup = `${place.formatted_address}`
})
}
I'm confused with Axios:
In my Vue template I have a list of JS objects, each element is like:
covs.all_batches_tuples[
...
{'id': 45, 'bname': 'tcp_S1153', 'selected': False}
...
]
I have a checkbox loop:
<v-row>
<v-col v-for="batch in covs.all_batches_tuples" :key="batch.id" class="pa-0 ma-0 text-body-2" cols="1">
<input type="checkbox" :id="batch.id" v-model="batch.selected" :value="batch.bname"
#click="selected_batches()"/>
<label :for="batch.id">{{ batch.bname }}</label>
</v-col>
</v-row>
and finally I have a method that is fired after clicking a checkbox:
methods: {
selected_batches() {
console.log("1 ", this.covs.all_batches_tuples)
axios({
method: 'post',
url: 'http://192.168.21.152:8002/showAnns/covs/',
data: {
checked_batches_ids_string: this.covs.all_batches_tuples,
},
})
console.log("2 ", this.covs.all_batches_tuples)
},
}
In Chrome the initial state looks like this:
when I click a checkbox, the selected_batches method fires two console.log() functions, and axios funciton.
All variables (this.covs.all_batches_tuples) are the same variables and in console.log looks good, the checkbox is selected:
But in axios post it as unselected:
If I click this checkbox again, so it is "unchecked", the axios shows it as "checked":
What is going on here? Thanks for help!
This problem actually happens because the v-model update later after the axios is called. In this case, you can use #change instead of #input.
<v-row>
<v-col v-for="batch in covs.all_batches_tuples" :key="batch.id" class="pa-0 ma-0 text-body-2" cols="1">
<input type="checkbox" :id="batch.id" v-model="batch.selected" :value="batch.bname" #change="selected_batches" />
<label :for="batch.id">{{ batch.bname }}</label>
</v-col>
</v-row>