In my vue application I have a nested array where the user can select one date and multiple times and this is saved as one object. What I want to achieve now is to display the date as a header (Works) and under it display all times belonging to that specific date. Right now I could only make it work with one time. But if one object has multiple times I still could only make it work to show one time.
Could someone take a look at my code?
code to display the insides of the array:
<v-card-text >
<v-row>
<v-col cols="4" v-for="(i, index) in datesFinal" >
<h4>{{i.date}}</h4>
<v-chip>{{i.times[0].startTime + ":" + i.times[0].endTime}}</v-chip>
</v-col>
</v-row>
</v-card-text>
Script tag:
<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.selectedTime = [];
}
My method does not work because I am telling it to access [0] but this is just my guess
You could try this solution::
<v-card-text>
<v-row>
<v-col cols="4" v-for="(item, index) in datesFinal" :key="index" >
<h4>{{item.date}}</h4>
<v-chip-group v-if="item.times.length !== 0">
<v-chip v-for="(time, i) in item.times" :key="i">
{{time.startTime + ":" + time.endTime}}
</v-chip>
</v-chip-group>
<v-chip-group v-else>
<v-chip>no times </v-chip>
</v-chip-group>
</v-col>
</v-row>
</v-card-text>
Ummm, I think I can provide a thinking that maybe you can use Set to filter the same date. Then use every item of this set to gather the same date's time from the object.
Related
I'm using nuxt, vuetify and firebase (cloud firestore for database) to build a contractor's database app. There will be a multiple of scope of works (SOW) & specializations for contractor to choose from when they filling a form.
For 1 scope of work, there will be multiple choices of specialization. So, whenever the user choose a SOW on the first select option, there will be just a limited number of specialization to choose from on the second select option that related to that particular SOW. After picking the specialization, the 3rd select option will auto display the code assigned to that specialization. All the data for SOWs & specializations is get from firestore database.
I have no problem to load the data from firestore for all 3 options. It just that it not do the dynamic dropdown the way I wanted.
I already referred to https://jsfiddle.net/mani04/Lgxrcc5p/ but cant really working out the solution. Is there an a way to do this?
Image of the 3 select options here : After select scope, nothing happen on the 2nd select
Thanks!
Here is my template code using vuetify v-select
<v-col cols="12" sm="6" md="5">
<v-select
:items="scope"
item-text="scope"
v-model="editedItem.scope"
label="Scope"
#click="listofscope"
></v-select>
</v-col>
<v-col cols="12" sm="6" md="5">
<v-select
:items="special"
item-text="specialization"
v-model="editedItem.specialization"
:disabled="listofspecialization.length == 0"
label="Specialization"
#click="listofspecialization"
></v-select>
</v-col>
<v-col cols="12" sm="6" md="5">
<v-select
:items="special"
item-text="code"
v-model="editedItem.code"
:disabled="listofspecialization.length == 0"
label="Code"
#click="listofspecialization"
></v-select>
</v-col>
Here is my script part
data: () => ({
// ..my other codes
scope: [],
editedIndex: -1,
editedItem: {
scope: '',
},
defaultItem: {
scope: '',
},
special: [],
editedIndex: -1,
editedItem: {
specialization: '',
code: '',
},
defaultItem: {
specialization: '',
code: '',
},
)}
listofscope() {
this.scope = []
db
.collection('Scope of Works')
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
this.scope.push({ ...doc.data(), id: doc.id })
})
if (this.listofscope.length > 0) {
this.listofspecialization = [this.scope]
}
console.log(this.scope)
})
},
listofspecialization() {
this.special = []
db
.collectionGroup("Specialization")
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
this.special.push({ ...doc.data(), id: doc.id })
})
if (this.listofspecialization.length > 0) {
this.code = [this.scope][this.specialization]
}
console.log(this.special)
})
I put my answer here in case if someone had the same problem with me. Yes, using watchers solved the problem.
Now, whenever I pick a scope, a limited choice of specialization will list out. Then, when I picked a specialization, it will automatically display the code assigned to that particular specialization.
Here's how I do it:
My HTML part:
<v-col cols="12" sm="6" md="5">
<v-select
:items="scopes"
item-text="scope"
v-model="editedItem.scope"
label="Scope"
></v-select>
</v-col>
<v-col cols="12" sm="6" md="5">
<v-select
:items="specializationFiltered"
item-text="specialization"
v-model="editedItem.specialization"
label="Specialization"
return-object
:disabled="specializations.length == 0"
></v-select>
</v-col>
<v-col cols="12" sm="6" md="5">
<v-select
:items="codes"
item-text="code"
v-model="editedItem.specialization.code"
label="Code"
:disabled="true"
></v-select>
</v-col>
My script part
watch: {
"editedItem.scope"(newVal) {
this.specializationFiltered = [];
if (this.editedItem.scope) {
firestore
.collection("Scope of Works")
.doc(this.editedItem.scope)
.collection("Specialization")
.get()
.then(querySnapshot => {
console.log(querySnapshot);
querySnapshot.forEach(doc => {
console.log(doc.data());
this.specializationFiltered.push(doc.data());
});
});
}
}
},
Thanks :))
I have a vue application where I have to select two elements from an list component and then put them inside an array.Right now I have my list and I can select them thanks to vuetify I binded it to an array with v-model I can console log it inside of an array but what I want to achieve is something like this:
{
"meetingName":"",
"meetingUrl":"",
"participants":{
participant1: "Hasan",
participant2: "Turan"
}
}
instead I am getting right now this:
{
"meetingName":"",
"meetingUrl":"",
"participants":[
"Hasan",
"Turan"
]
}
Could someone look at my code and tell me what is wrong with it?
html:
<template>
<v-container>
<v-row>
<v-col cols="4">
<v-card>
<v-list>
<v-list-item-group
v-model="model"
multiple
color="indigo"
v-model="model.participants"
>
<v-list-item
v-for="(item, i) in voterArrayFilteredByTime"
:key="item.voterUniqueName"
:value="item.voterUniqueName"
v-on:click= "generateGroup"
>
<v-list-item-content>
<v-list-item-title v-text="item.voterUniqueName"></v-list-item-title>
</v-list-item-content>
</v-list-item>
</v-list-item-group>
</v-list>
</v-card>
</v-col>
</v-container>
</template>
an here is the method with which I want to console log it but it does not work like I said I am just getting numbers.
<script>
import axios from "axios";
export default {
name: "AddGroupsModal",
data : ()=>({
singleSelect: false,
selection: "",
model:{ meetingName: "", meetingUrl: "", participants: [] },
methods: {
generateGroup(){
console.log(this.model)
}
}
</script>
One of the problems in your markup is it has two bindings to v-model when there should be just one (the last one in this case):
<v-list-item-group
v-model="model"❌
multiple
color="indigo"
v-model="model.participants"❌
>
The v-list components can't create the expected value format, but you can use a computed prop along with Array.prototype.reduce to create an object from the array entries:
export default {
computed: {
computedParticipants() {
return this.model.participants.reduce((obj, name, i) => {
obj[`participant${i + 1}`] = name
return obj
}, {})
// OR:
const obj = {}
this.model.participants.forEach((name, i) => {
obj[`participant${i + 1}`] = name
})
return obj
},
},
}
demo
I want :value to change from inputValue.start to inputValue.end automatically.
So when I click on the end date it should be updated in the second text field. Likewise, if I select a date range in the second text field, the first text field should also be updated again.
At the end of this question you can see the result of both cases.
P.S.: I use the V-Calendar plugin for Vue.js. The vc-date-picker element is from this plugin.
HTML:
<v-col v-for="(dateF, date_id) in datesF" :key="date_id + 'A'" cols="6" sm="3">
<vc-date-picker v-model="range" color="red" is-range :input-debounce="500" :min-date="new Date()">
<template v-slot="{ inputValue, inputEvents }">
<v-text-field
:value="inputValue.start"
v-on="inputEvents.start"
:label="dateF.label"
/>
</template>
</vc-date-picker>
</v-col>
Script:
<script>
export default {
name: "Home",
data: () => ({
datesF: [
{ label: "Start Date", val: "start" },
{ label: "End Date", val: "end" },
],
range: {
start: new Date(),
end: new Date(),
},
}),
};
</script>
Result 1
Result 2
What I tried:
:value="inputValue + '.' + dateF.val" but that wasn't the solution.
EDIT:
Without v-for and twice v-text-field it works, but I want to use v-for. The reason is that otherwise I can't put the text fields in one line. No matter what I did, it didn't work. It only works with v-for, but for that I have to solve the main problem.
Temporary Solution (with v-for)
See answer of #Gurkan Ugurlu.
The problem of this temporary solution:
No Live Update. See GIF.
For Live Update my initial code:
I just output the data for testing and it worked. Every time you select a date range, console.log is executed with the current dates.
watch: {
range: {
handler: function () {
console.log(this.range.start.toLocaleDateString());
console.log(this.range.end.toLocaleDateString());
},
},
},
Can you try this? Hope it helps :)
<v-col v-for="(dateF, date_id) in datesF" :key="date_id + 'A'" cols="6" sm="3">
<vc-date-picker v-model="range" color="red" is-range :input-debounce="500" :min-date="new Date()">
<template v-slot="{ inputValue, inputEvents }">
<v-text-field
:value="inputValue[dateF.val]"
v-on="inputEvents[dateF.val]"
:label="dateF.label"
/>
</template>
</vc-date-picker>
</v-col>
I need to get VuetifyJS advanced slots to work with the Google Places API. Currently some addresses only show up in the autocomplete dropdown after clicking the "x" in the form field to delete the input text.
Here is a CodePen demonstrating the issue:
https://codepen.io/vgrem/pen/Bvwzza
EDIT: I just found out that populating the dropdown menu with the suggestions is the issue. The suggestions are visible in the console.log but not in the dropdown. Any ideas how to fix this issue?
(Some addresses work right away, some not at all - it's pretty random.
Any ideas on how to fix this are very welcome.)
JS:
new Vue({
el: "#app",
data: () => ({
isLoading: false,
items: [],
model: null,
search: null,
}),
watch: {
search(val) {
if (!val) {
return;
}
this.isLoading = true;
const service = new google.maps.places.AutocompleteService();
service.getQueryPredictions({ input: val }, (predictions, status) => {
if (status != google.maps.places.PlacesServiceStatus.OK) {
return;
}
this.items = predictions.map(prediction => {
return {
id: prediction.id,
name: prediction.description,
};
});
this.isLoading = false;
});
}
}
});
HTML:
<div id="app">
<v-app id="inspire">
<v-toolbar color="orange accent-1" prominent tabs>
<v-toolbar-side-icon></v-toolbar-side-icon>
<v-toolbar-title class="title mr-4">Place</v-toolbar-title>
<v-autocomplete
v-model="model"
:items="items"
:loading="isLoading"
:search-input.sync="search"
chips
clearable
hide-details
hide-selected
item-text="name"
item-value="symbol"
label="Search for a place..."
solo
>
<template slot="no-data">
<v-list-tile>
<v-list-tile-title>
Search for a <strong>Place</strong>
</v-list-tile-title>
</v-list-tile>
</template>
<template slot="selection" slot-scope="{ item, selected }">
<v-chip :selected="selected" color="blue-grey" class="white--text">
<v-icon left>mdi-map-marker</v-icon>
<span v-text="item.name"></span>
</v-chip>
</template>
<template slot="item" slot-scope="{ item, tile }">
<v-list-tile-avatar
color="indigo"
class="headline font-weight-light white--text"
>
{{ item.name.charAt(0) }}
</v-list-tile-avatar>
<v-list-tile-content>
<v-list-tile-title v-text="item.name"></v-list-tile-title>
<v-list-tile-sub-title v-text="item.symbol"></v-list-tile-sub-title>
</v-list-tile-content>
<v-list-tile-action> <v-icon>mdi-map-marker</v-icon> </v-list-tile-action>
</template>
</v-autocomplete>
<v-tabs
slot="extension"
:hide-slider="!model"
color="transparent"
slider-color="blue-grey"
>
<v-tab :disabled="!model">Places</v-tab>
</v-tabs>
</v-toolbar>
</v-app>
</div>
(I enabled the relevant API's in Google Cloud.)
the problem is the number of request you do in a certain amount of time. Every character triggers an request to the GoogleApi which is resulting in.
I think the error_message isn't totally correct while I trying afterwards it gives me a result.
To solve this,
upgrade your GoogleApi account
Debounce your input. so wait till the customer is not typing for half a second and then sen a request to The googleApi. You could use lodash to implement to debounce functionality https://lodash.com/docs/#debounce
I'm creating a button to filter those data(games) that a user bought or have though in my code it only filters data with no boolean attribute set upon them.
Edited: added some more details on the code with firebase data to ref
<!-- This is the button I'm having trouble with -->
<v-tooltip right>
<v-btn small flat color="grey" #click="toggleHave(true)" slot="activator">
<v-icon left small>title</v-icon>
<span class="caption text-lowercase">by All titles bought</span>
</v-btn>
<span>Sort by Game's Title that I have</span>
</v-tooltip>
</v-flex>
<!-- filterGames is for the search method -->
<v-layout row wrap>
<v-card v-for="game in filterGames" :key="game.id" class="ma-2" width="240px">
<router-link :to="{ name: 'view-game', params: { game_id: game.game_id }}">
<v-img :src="game.cover" :alt="game.name" />
</router-link>
<v-card-title>
<div>
<span class="subheading">{{ game.title }}</span><br>
<span class="caption grey--text">{{ game.platform }}</span><br>
</div>
</v-card-title>
</v-card>
</v-layout>
export default {
data() {
return {
games: [], //this is connected to firebase
search: '',
}
},
toggleHave(bought) {
console.log(bought)
this.games = this.games.filter(game => {
return game.have === bought.have
})
},
computed: {
filterGames() {
return this.games.filter((game) => {
return game.title.toLowerCase().match(this.search)
})
}
}
}
// with true
game_id: "006"
title: "Far Cry 4"
have: true // this is the boolean
// with false
game_id: "051"
title: "Assassin's Creed Unity"
have: false // this is the boolean
You're calling toggleHave(true), but in your toggleHave function you use argument as it was an object:
game.have === bought.have
That means you compare game.have with undefined, which explains current behaviour.
Replace bought.have with bought and it should work.
Your question is more of a JavaScript question then a vue question. The filter function returns an array of the elements that meet your condition see here
If you would like to receive Boolean on filtering try using the includes method like here
see this Filter list with Vue.js
just change
return this.games.filter(game => {
return game.have == bought
})