How to create q-radio input with multiple different models dynamically - vue.js

I am using the quasar framework with VueJS 3 Composition API,
I am receiving some responses from an API and according to the API I am trying to generate some checkboxes and radio input dynamically. I generated the q-checkbox element but I am facing an issue with q-radio because I have to have multiple radio groups with multiple options. so please guide me on how can I achieve this.
Here is the snippet of code that I tried so far.
Html template part
<q-item
disable
tag="label"
v-ripple
v-for="(item, index1) in optGroup.optionsItem"
:key="index1"
>
<q-item-section avatar>
<q-radio
v-model="selectedVariantIds[index]"
:val="item.id"
color="primary"
v-if="optGroup.option_type == 'radio'"
/>
<q-checkbox
v-model="selectedAddonIds"
:disabled="
optGroup.max_select != 0 &&
selectedAddonIds.length >= optGroup.max_select
"
:val="item.id"
color="primary"
v-if="optGroup.option_type == 'checkbox'"
/>
</q-item-section>
<q-item-section>
<q-item-label lines="1" class="pc font-regular fs-16">{{
item.option_item_name
}}</q-item-label>
<q-item-label caption class="sc font-regular fs-14"
>{{ item.currency_symbol != "" ? item.currency_symbol : "$"
}}{{ item.option_sale_price }}</q-item-label
>
</q-item-section>
</q-item>
Script
const selectedAddonIds = ref([]);
const selectedVariantIds = ref([]);
I am able to get the selected Addons as array after checking some checkboxes but the problem is with the variants as they are the radio input it is giving the single value even the radio input is from a different group.

Related

How can we find out the parent element in which the vue draggable is dropped?

There are multiple v-autocompletes and I want to know which v-autocomplete is my draggable element dropped in So that I can rearrange them properly. If I try to move the v-chips (draggable component) into another v-autocomplete it does not get positioned properly. I am using vue-draggable library, any kind of help will be appreciated thanks!!
v-autocomplete(
v-for="(cabinet, index) in cabinets"
:key="index"
v-model="selectedSystemCabinets[cabinet-1]"
#input="updateSelectedSystems()"
:items="systems"
:label="$t('Controllers')"
:rules="rules.nonEmptyArray"
:id="cabinet"
chips
multiple
return-object
outlined
color="primary"
item-text="name"
item-value="systemID"
)
template(#selection="data")
draggable(
:id="data.index"
:list="selectedSystemCabinets[cabinet-1]"
v-bind="dragOptions"
:move="move"
:group="{name: 'controllers', put: true}"
#change="change(cabinet, $event)"
#start="isDragging = true"
#end="endDrag"
)
v-chip(
draggable
:ripple="false"
:key="data.index"
v-model="selectedSystemCabinets[cabinet-1][data.index]"
#mousedown.stop
#click:close="remove(cabinet, data.index)"
#click.stop
style="cursor: move;"
:color="((isDragging && data.index === dragged.from) ? 'success' : 'primary')"
close
outlined
).ma-2
span {{ data.item.name }}
v-chip(
x-small
color="primary"
).primary-chip
span(v-if="showPrimary(data) && cabinet === 1").text-uppercase {{ $t('primary') }}
span(v-else) {{ getOrderNumber(data.index) }}

Vue show next 10 items when press button

I'm trying to do load more function. When load more button is clicked show next 10 hidden items in v-for allCategories loop.
<template v-for="(category, i) in allCategories">
<v-col :key="i" v-show="i <= 10" class="col-6 col-sm-4">
<v-checkbox
dense
color="black"
:label="category.title"
:value="isCategoryChecked(category.id)"
#click="() => selectCategory(category.id)"
/>
</v-col>
</template>
load more button
<v-btn color="black white--text"
#click="showMoreCategories"
:loading="loading">
{{ $t('general.loadMore') }}
</v-btn>
showMoreCategories function
showMoreCategories() {
}
How do i implement this?
Assuming your variable allCategories contains all the categories you could possibly want (i.e. you don't have to fetch additional categories from a server or local store) then you can replace v-show="i <= 10" with v-show="i <= numberOfCategoriesToShow". Where numberOfCategoriesToShow is a new variable you have defined and initially set to 10.
Then your showMoreCategories function would look like this
showMoreCategories() {
this.numberOfCategoriesToShow += 10;
}

Is there a way to toggle visibility for multiple password fields with a dynamic form using vuetify vuejs?

I have a dynamic form that is constructed based off of json from the backend of input types, id, names, values, etc. One of my forms has two password fields that come from the backend. Is there a way to toggle visibility for multiple password fields on the same dynamic form? I'm having trouble figuring out how to do this to one at a time. Right now, the toggle icon switches both password fields on the screen.
<template>
<div class="pb-4" >
<template v-for="formField in formFields">
<v-row
:key="formField.key"
dense
align="center"
>
<v-col
md="3"
class="font-weight-bold text-right pr-10"
align-self="center"
>
{{formField.name}}
<span v-if="formField.required" class="small"> *</span>
</v-col>
<v-col
md="8"
align-self="center"
class="pl-3"
>
<v-text-field
v-if="formField.type === 'password'"
:id="formField.key"
:key="formField.key"
v-model="formField.value"
:append-icon="showPasswordIcon ? '$vuetify.icons.values.eye' : '$vuetify.icons.values.eyeSlash'"
:type="showPasswordIcon ? 'text' : 'password'"
:hint="getHintText(formField)"
:value="formField.name"
:required="formField.required"
:valid="(!formField.isValid) ? false : undefined"
dense
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
#click:append="showPasswordIcon = !showPasswordIcon"
/>
<v-text-field
v-if="formField.type === 'text'"
:id="formField.key"
v-model="formField.value"
dense
:valid="(!formField.isValid) ? false : undefined"
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
/>
<v-checkbox
v-if="formField.type === 'boolean'"
:id="formField.key"
v-model="formField.value"
class="mt-2"
/>
<v-text-field
v-if="formField.type === 'number'"
:id="formField.key"
v-model.number="formField.value"
dense
:valid="(!formField.isValid) ? false : undefined"
class="mb-0"
type="number"
#input="inputHandler(formField)"
#blur="inputHandler(formField, false)"
/>
</v-col>
</v-row>
</template>
</div>
</template>
Thank you so much for any tips on this!
Easiest solution might be to add an extra property to each element in the formFields, like visible, that tracks if a password should show its text. You can do that on API response and then insert it.
Then in your loop you can do
:type="formField.visible ? 'text' : 'password'"
This way, every formField is responsible for their own password visibility.
Next, you change
#click:append="showPasswordIcon = !showPasswordIcon"
to
#click:append="toggleShowPassword(formField.key)"
toggleShowPassword(key){
let formfield = this.formfields.find(x => x.key === key)
if(formfield){
formfield.visible = !formfield.visible
}
}
That should work!

Vue Bootstrap, how to interact with plus/minus icon on dynamic generated collapse content separately

I have a VueJS view that creates collapsed contents using Bootstrap Vue Collapse Component.
The data is dynamic and can contains hundreds of items, which is why you see in the code below it was created via a v-for loop in Vue.
<div class="inventory-detail" v-for="(partNumberGroup,index) in inventory" :key="index" >
<b-button block v-b-toggle="partNumberGroup.partNumber" v-bind:id="partNumberGroup.partNumber" variant="primary"
#click="(evt) =>{isActive = !isActive && evt.target.id == partNumberGroup.partNumber}">
<i v-bind:id="partNumberGroup.partNumber" class="float-right fa" :class="{ 'fa-plus': !isActive, 'fa-minus': isActive }"></i>
{{ partNumberGroup.partNumber }}
</b-button>
<div class="inventory-detail__card" v-for="item in partNumberGroup.items">
<b-collapse v-bind:id="partNumberGroup.partNumber" >
<b-card>
<!--Accordion/Collapse content -->
</b-card>
</b-collapse>
</div>
</div>
This works fairly well in that I can individually expand and collapse each content separately. However, the one issue I'm facing is each time I click the icon fa-minus (-) orfa-plus (+), all of them changed as per the images below.
Any tips on how I should implementing this? in my code I tried the dynamic CSS class switching but I still lack the ability to switch on specific element.
I feel like the solution to this is to somehow conditionally apply dynamic CSS class or somehow able to use the attribute 'aria-expanded'.
You can try something like this. Whenever somebody clicks on the icon, set its index as activeIndex (using the setActiveIndex method). Then you can set the class accordingly by comparing the activeIndex with current index
<i
#click="setActiveIndex(index)"
v-bind:id="partNumberGroup.partNumber"
class="float-right fa"
:class="{ 'fa-plus': !isActive(index), 'fa-minus': isActive(index) }">.
</i>
then in the script part:
...
data() {
return {
activeIndex: -1
}
},
methods: {
/* set active index on click */
setActiveIndex(index) {
this.activeIndex = index;
},
/* check if index is active or not */
isActive(index) {
return index === this.activeIndex;
}
}

Vue-Multiselect Plugin: How to safely remove "add a new" tag functionality?

I am using a plugin called Vue-Multiselect and have it working pretty good on my app. However, there is a functionality in the plugin that I do no want. How can I safely remove it?
Let me explain: CodeSandBox Collaboration Editor .
Note: To see this flow in action, choose EDIT next to ACME Widget and then search for an on existent user in the multiselect input box.
When a user is searched for in the multiselect input box, and if a match is found, the match pops up for the user to select. That is good. However, when a user is NOT found, there's a placeholder text that says the following: Press enter to create a tag . I do NOT want to give my users the ability to create new tags/options if the option does not exist. How can I remove that functionality from this component?
Here is my multi-select component code:
<multiselect
id="customer_last_name_input"
v-model="values"
:options="options"
label="lastname"
placeholder="Select or search for an existing customer"
track-by="uid"
:loading="isLoading"
:custom-label="customerSelectName"
aria-describedby="searchHelpBlock"
selectLabel
:multiple="true"
:taggable="true"
>
<template
slot="singleLabel"
slot-scope="props"
>{{ props.option.lastname }}, {{props.option.firstname}}</template>
<template slot="option" slot-scope="props">
<strong>{{ props.option.lastname }}</strong>
, {{ props.option.firstname }} —
<small>{{ props.option.email }}</small>
</template>
<!-- <template slot="noResult">Looks like this customer doesn't exist yet.<button class="btn btn-primary" type="button" #click="addCustomer">Add Customer</button></template> -->
</multiselect>
I found the answer. I simply remove the taggle=true prop from the multiselect component.