Why is my :search-input.sync function called twice? - javascript

In my code pen https://codepen.io/aaronk488/pen/MWbKNOq?editors=1011 everything works, but my sync function search is called twice and I don't know why. I added a conditional statement so my code works, but am curious if there is a reason why the sync function is called twice.
Here is my HTML
<div id="app">
<v-app>
<v-container >
<v-row >
<v-col cols="4" md="4">
<v-autocomplete
ref="autocomplete"
label="Autocomplete"
:items="components"
v-model="first"
:search-input.sync="search"
hint="need to open menu on focus, just like click" persistent-hint
></v-autocomplete>
</v-col>
<v-col cols="4" md="4">
<v-autocomplete
v-model="second"
ref="autocomplete2"
label="Autocomplete2"
:items="components2"
item-text="name"
item-value="id"
hint="need to open menu on focus, just like click this" persistent-hint
></v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-app>
</div>
and here is my js
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
search: null,
first: "",
second: "",
components: [
'Autocompletes testOne', 'Comboboxes testTwo', 'Forms', 'Inputs', 'Overflow Buttons', 'Selects', 'Selection Controls', 'Sliders', 'Textareas', 'Text Fields',
],
components2: [
'Autocompletes2', 'Comboboxes2', 'Forms2', 'Inputs2', 'Overflow Buttons2', 'Selects2', 'Selection Controls2', 'Sliders2', 'Textareas2', 'Text Fields2',
],
},
watch: {
search(val){
if(val){
console.log(val)
const temp = val.split(" ");
console.log(temp)
// this.components = [];
// this.components2 = [];
this.components.push(temp[0]);
console.log(this.components);
if(!temp[1]){
return;
}
console.log(temp[1]);
this.components2.push(temp[1]);
this.first = temp[0];
this.second = temp[1];
console.log(this.second )
}
},
},
})
and here is the console output

You're changing the property bound with v-model to that search input in your watcher. This line:
this.first = temp[0];
since this first property is bound with v-model, it's changing the search-input. You'll notice it doesn't happen if you select an item with only one word, because that single word will be the same as temp[0].

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.

Vuetify autocomplete both menus active at the same time

Here is my code pen https://codepen.io/aaronk488/pen/MWbKNOq?editors=1011
Here is the HTML
<div id="app">
<v-app>
<v-container >
<v-row >
<v-col cols="6" md="6">
<v-autocomplete
ref="autocomplete"
label="Autocomplete"
:items="components"
hint="need to open menu on focus, just like click" persistent-hint
></v-autocomplete>
</v-col>
<v-col cols="6" md="6">
<v-autocomplete
ref="autocomplete2"
label="Autocomplete2"
:items="components2"
hint="need to open menu on focus, just like click this" persistent-hint
></v-autocomplete>
</v-col>
</v-row>
</v-container>
</v-app>
</div>
and here is the JS
new Vue({
el: "#app",
vuetify: new Vuetify(),
data: {
components: [
'Autocompletes', 'Comboboxes', 'Forms', 'Inputs', 'Overflow Buttons', 'Selects', 'Selection Controls', 'Sliders', 'Textareas', 'Text Fields',
],
components2: [
'Autocompletes2', 'Comboboxes2', 'Forms2', 'Inputs2', 'Overflow Buttons2', 'Selects2', 'Selection Controls2', 'Sliders2', 'Textareas2', 'Text Fields2',
],
},
mounted () {
let autocompleteInput = this.$refs.autocomplete.$refs.input
autocompleteInput.addEventListener('focus', this.onFocus, true)
let autocompleteInput2 = this.$refs.autocomplete2.$refs.input
autocompleteInput2.addEventListener('focus', this.onFocus2, true)
},
methods: {
onFocus() {
this.$refs.autocomplete.isMenuActive = true
this.$refs.autocomplete.isMenuActive = true
},
onFocus2() {
this.$refs.autocomplete.isMenuActive = true
}
}
})
Here is what the UI looks like
Is there a way to get both v-autocomplete menu to show at the exact same time?
If the user clicks on either v-autocomplete both that v-autocomplete and the other v-autocomplete drop-downs with the options show at the same time.
Set isMenuActive && isFocused to true
this.$refs.example.isMenuActive = true;
this.$refs.example.isFocused = true;

How to add a google autocomplete input inside of a vuetify dialog box

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}`
})
}

Categories