V-autocomplete not updating on user interaction - vuejs2

I am having 3 multi-select elements on a page and one button. On click on the button, I want whatever the value selected on the third i.e last multi-select element, shall get selected on all top two multi-select elements. On clicking on button, i do see the values are getting updated in vuex.state.vModelValues based on the given key, but the updated values are not reflecting on the first 2 multi-select.
Note: I need to get/set the value of the first 2 multi-select from a JSON object based on the key/value pair. I can use an individual array with v-model with first 2 multi-select element, but i don't want to go with that approach as i may have 100 multi-selects element and can't define 100 array in data section. So want to define a JSON which will hold the key/value for each multi-selects and should be reactive. If the value of one entry change, the key that mapped to multi-select shall get updated immediately.
I am not sure what i am doing wrong here. The value are updated on store but the updated value are not get selected on UI. Please help.
Below is my code:
1. STORE
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
state() {
return {
vModelValues: {},
};
},
getters: {
getVModelPlaceholder(state) {
return state.vModelValues;
},
getVModelValue(state, key) {
return state.vModelValues[key];
},
},
mutations: {
setVModelValue(state, payload) {
state.vModelValues[payload.key] = payload.value;
},
},
actions: {
setVModelValue(context, payload) {
context.commit("setVModelValue", payload);
},
},
modules: {},
});
APP.VUE
<template>
<v-app>
<v-main>
<HelloWorld />
</v-main>
</v-app>
</template>
<script>
import HelloWorld from "./components/HelloWorld";
export default {
name: "App",
components: {
HelloWorld,
},
data: () => ({}),
mounted: function () {
this.$store.dispatch("setVModelValue", {
key: "listbox_checkbox_ID1",
value: ["Three"],
});
this.$store.dispatch("setVModelValue", {
key: "listbox_checkbox_ID2",
value: ["Two"],
});
},
};
</script>
HelloWorld.vue
<template>
<v-container>
<div id="container_dummy_PID1" style="height: auto; width: 100%">
<v-autocomplete
id="listbox_checkbox_1"
:items="ranges"
v-model="$store.state.vModelValues['listbox_checkbox_ID1']"
hide-details
multiple
dense
return-object
cache-items
>
</v-autocomplete>
<v-autocomplete
id="listbox_checkbox_2"
:items="ranges"
v-model="$store.state.vModelValues['listbox_checkbox_ID2']"
hide-details
multiple
dense
return-object
cache-items
>
</v-autocomplete>
<v-autocomplete
v-model="selectedValues"
:items="ranges"
hide-details
multiple
dense
required
return-object
>
</v-autocomplete>
<v-btn color="primary" #click="applyToAll()">Apply to All</v-btn>
</div>
</v-container>
</template>
<script>
export default {
name: "HelloWorld",
data() {
return {
selectedValues: "",
ranges: ["One", "Two", "Three", "Four", "Five"],
};
},
methods: {
applyToAll() {
this.$store.dispatch("setVModelValue", {
key: "listbox_checkbox_ID1",
value: this.selectedValues,
});
this.$store.dispatch("setVModelValue", {
key: "listbox_checkbox_ID2",
value: this.selectedValues,
});
},
},
};
</script>

Related

Export v-Select Values to print in another component - Vuetify

I have a v-select list box in one component (RoadsType.vue) and its items are listed in data in export default.
<v-select v-model="position"
:items="gps_items"
:loading="loading"
label="GPS R-Positioning"
:color="color"
></v-select>
export default {
data() {
return {
gps_items: ["0", "5", "7", "10", "15", "Random"]
};
}, }
Now on selecting the item in the v-select input box, I want the output to be shown in another component's (Summary.vue) v-card text box, by calling a function.
<v-card title="Environment"
:subtitle="getPosition"
</v-card>
getPosition() {
return `GPS R-Positioning: ${this.position}`;
}
But the output doesn't print if I call the v-model of the v-select box. What should be done?
If they are on the same page you can emit the value of RoadType.vue
// RoadType.vue
export default {
data() {
return {
gps_items: ['0', '5', '7', '10', '15', 'Random']
};
},
watch: {
position(value) {
this.$emit('position', value)
}
}
};
and then on sample-page.vue you can pass the data to Summary.vue by using props
// sample-page.vue
<template>
<div>
<RoadsType #position="getPosition"/>
<Summary :position="position"/>
</div>
</template>
<script>
export default {
data() {
return {
position: ''
};
},
methods: {
getPosition(position) {
this.position = position
}
},
};
</script>
Add props on Summary.vue
// Summary.vue
<template>
<div>
<v-card title="Environment" :subtitle="getPosition"> </v-card>
</div>
</template>
<script>
export default {
props: {
position: {
type: String,
default: ''
}
},
computed: {
getPosition() {
return `GPS R-Positioning: ${this.position}`;
}
}
};
</script>
or you could also use Vuex aswell to simply it.

v-select component from child to parent binding when editing

I'm running again another issue on my code, that although I can save the v-select component. I have 2 of these, the another is good in which the type items are object. The problem is by clicking edit button and passing value from child component to parent component, when I console the issue in edit method, I can see the output in console but it does not display on the imported component which is claimsdropdown. And when I update the another v-select imported component named type, the claimsdropdown value is passing null, that although it has already value in it based on fetching from database.
Here is my v-select component stuff:
<template>
<v-select
:items="items"
item-text="text"
item-value="value"
v-model="selected"
return-object
:menu-props="{ bottom: true, offsetY: true }"
append-icon="fas fa-chevron-down"
placeholder="Claims"
outlined
dense
/>
</template>
<script>
import { mapState } from "vuex"
export default {
name: "ClaimsDropdown",
data: () => ({
items: [
{
text: "Yes",
value: true
},
{
text: "No",
value: false
}
]
}),
computed: {
...mapState({
selected: state => state.projects.selected
}),
selected: {
get() {
return this.$store.state.projects.selected;
},
set(item) {
this.$store.commit("projects/SET_SELECTED", {
selected: item.value
});
this.$store.commit("projects/SET_FILTER_IS_CLAIMED", {
is_claimed: item?.value
});
}
}
}
};
</script>
<style scoped></style>
Parent Component:
<v-row>
<v-col cols="4">
<ClaimsDropdown v-model="this.selected.claim" />
</v-col>
</v-row>
on my computed:
computed: {
...mapState({
selected: state => state.projects.selected
})
}
and on method edit:
this.selected.claim = getFilterPresetsData.filters.claimed;
console.log({checkingClaim: this.selected.claim}); //display whatever the value from database.
Vuex: projects >name of vuex store
state: selected: null
my brain got drain by this one.

Reset select values in v-autocomplete, in order to add multiple items

I'm creating an application that has a selection box to choose between some template data. However, the user should be able to select the same template option several times and, each time he selects the template, a new informational box appears in the screen.
My problem is that the v-autocomplete component doesn't enable this kind of behavior: we can select one option (or multiple options), but not the same option twice.
I thought about making something like this: every time the user selects the option A, the infobox would appear below and the component would reset to a empty option. Then, the user could choose option A again and, when he chooses it, another info box would appear, how many times the user needs it.
How could I do something like this using vue? I didn't found any component that would do something like this on default, so I think I'll have to tweak the component behavior, but I don't know exactly where to start.
My template:
<template>
<div class="select-wrapper" id="selectBox">
<v-autocomplete
class="select-input"
:items="items"
:name="label"
placeholder="select item"
solo
:value="value"
#change="$event => onChange($event, items)"
item-text="name"
item-value="value"
:required="required"
:rules="[
value =>
!required ||
!!value ||
"required"
]"
></v-autocomplete>
</div>
</template>
And my Vue code:
<script lang="ts">
import { defineComponent } from "#vue/composition-api";
import Vue from "vue";
interface SelectItem {
name: string,
value: string
}
interface SelectBoxProps {
items: SelectItem[];
value: string;
onSelect: ({ target }: { target?: SelectItem }) => void;
hasResetSelection: boolean;
}
export default defineComponent({
name: "SelectBox",
props: {
label: String,
items: Array,
value: [String, Number],
onSelect: Function,
disabled: Boolean,
required: {
type: Boolean,
default: false
},
hasError: Boolean,
errorMessage: String,
hasResetSelection: {
type: Boolean,
default: false
}
},
directives: {
ClickOutside
},
setup({ onSelect, hasResetSelection }: SelectBoxProps) {
const onChange = (selectedValue: string, itemsArr: SelectItem[]) => {
const targetItem = itemsArr.find(i => i.value === selectedValue);
if (hasResetSelection) {
Vue.nextTick(() => {
console.log("onselect should reset value");
return onSelect({ target: { name: "", value: "" } });
});
}
return onSelect({ target: targetItem });
};
return {
onChange
};
}
});
</script>
This was my last attempt with Vue.nextTick, I already tried to tweak the component with ref() and it didn't work as well. Do you have any suggestions?
You can use another variable just to hold the input for the autocomplete component Like this:
var app = new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
items: [{ name : 'hello', value : 1 }, { name : 'world', value : 2 }],
value : null,
values : []
},
methods: {
onChange() {
this.values.push(this.value)
this.$nextTick(() => {
this.value = null
})
},
}
})
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.0"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-container>
Values : {{values}}
<v-autocomplete
:items="items"
placeholder="select item"
solo
v-model="value"
item-text="name"
item-value="value"
#change="onChange"
/>
</v-container>
</v-app>
</div>

NuxtJS component - component renders without data

I have a component that uses fetch to bring data via Axios and return data to render. I am using the store to set/get the data. The component renders with empty data and after debugging I see that data() method is called before fetch() method.
How to fix the problem and bring the data before the component is rendered
here is the component code:
<template>
<v-card
class="mx-auto"
max-width="500"
>
<v-sheet class="pa-4 primary lighten-2">
<v-text-field
v-model="search"
label="Search Company Directory"
dark
flat
solo-inverted
hide-details
clearable
clear-icon="mdi-close-circle-outline"
></v-text-field>
<v-checkbox
v-model="caseSensitive"
dark
hide-details
label="Case sensitive search"
></v-checkbox>
</v-sheet>
<v-card-text>
<v-treeview
:items="items"
:search="search"
:filter="filter"
:open.sync="open"
>
<template v-slot:prepend="{ item }">
<v-icon
v-if="item.children"
v-text="mdi-${item.id === 1 ? 'home-variant' : 'folder-network'}"
></v-icon>
</template>
</v-treeview>
</v-card-text>
</v-card>
</template>
<script>
export default {
async fetch(){
console.log("Hi from Fetch !!!")
let response = await this.$axios.get('/items/tasks', {baseURL: 'http://localhost:8055'});
let tasks = response.data.data;
debugger
this.$store.commit('SET_ASSIGNMENTS', tasks);
},
data () {
debugger
console.log("data assignments: ", this.$store.state.assignments);
return {
items: this.$store.state.assignments,
open: [1, 2],
search: null,
caseSensitive: false,
}
},
computed: {
filter () {
return this.caseSensitive
? (item, search, textKey) => item[textKey].indexOf(search) > -1
: undefined
},
}
}
</script>
For this I use vuex this way:
const appStore = {
state () {
return {
data: [],
}
},
getters: {
data(state) {
return state.data
},
},
mutations: {
SET_ASSIGNMENTS(state, payload) {
state.data = payload
},
},
actions: {
async getData({ commit }, {fromDate, toDate}) {
let response = await this.$axios.get('/items/tasks', {baseURL: 'http://localhost:8055'});
let tasks = response.data.data;
commit("SET_ASSIGNMENTS", tasks);
}
}
}
export default appStore
Component code is like this:
<template>
. . .
</template>
<script>
import { mapGetters } from 'vuex';
export default {
name: "MyComponent",
components: {
. . .
},
computed: {
...mapGetters({
data: 'data'
})
},
mounted(){
this.getData();
},
methods: {
getData() {
this.$store.dispatch('getData')
}
}
}
</script>
data is not reactive, you can create a computed property that returns your items
ex:reactiveItems() {return this.items}

How to get the values from the DOM controls when the models are created dynamically using vuejs

I am creating a dynamic form generator component in which the DOM controls to be displayed are getting populated from an API service. The model key i.e. the :v-model is also getting added dynamically. I am not able to access the data which the user inputs in the DOM control.
The component from where all the data is passed to the form-generator
<template>
<form-generator :schema="schema" :model="model" :options="formOptions"></form-generator>
</template>
<script>
export default {
components: {
FormGenerator
},
data() {
return {
model: {},
schema: {
fields: [{"id":"dcno1","label":"DC No.","model":"dcno","name":"dcno","ref":"dcno","className":"","type":"input","inputType":"text","required":true,"order":2}]
}
}
}
</script>
In the above code, model and schema.fields are getting populated from an async axios API call.
If we pass value in the model for the model named "dcno", the value is getting filled in the input control
Dynamic Form Generator Component
<template>
<v-form v-if='schema!==null' v-model="model.valid" ref="form" lazy-validation>
<v-flex xs6 v-for='(formItem,index) in schema.fields' v-bind:key='index'>
<v-text-field :v-model='formItem.model' ref="formItem.model"
:label='formItem.label' :rules='formItem.rules'
:value='model[formItem.model]'
:type='formItem.inputType' :value='model[formItem.model]'
:id='formItem.id'>
</v-text-field>
</v-flex>
<v-btn class='float-right' color="primary" #click="submitForm">Submit</v-btn>
</v-form>
</template>
<script>
export default {
name: 'form-generator',
components: {
},
props: {
schema: Object,
model: Object
},
methods:{
submitForm: function(e) {
//how to access the form model values here
}
}
}
</script>
When passed a static value to model dcno, :value='model[formItem.model]', the value is getting displayed.
Consider the fields key has a set of controls.
Please help me in getting the values of the form in the submit function.
As you can see in the docs you cannot change the value of a component property, you need to create a support object inside the inner component and emit its value to the main component. Take a look at the example, i create innerModel based on the schema structure then i emit every changes to the innerModel by watching it.
Vue.config.devtools = false;
Vue.config.productionTip = false;
const formGenerator = Vue.component('form-generator', {
props: ['schema', 'value'],
data() {
return {
innerModel: [],
}
},
watch: {
schema: {
deep: true,
immediate: true,
handler() {
this.innerModel = this.schema.fields.map((field) => ({
// pass here any other property you need
name: field.name,
value: field.model,
}));
},
},
innerModel: {
deep: true,
immediate: true,
handler(value) {
this.$emit('input', value);
},
}
},
methods: {
submitForm: function(e) {
e.preventDefault();
// convert innerModel into an object if needed
console.log(this.innerModel);
}
},
template: `
<form #submit="submitForm">
<input
:key="model.name"
v-model="model.value"
v-for="model in innerModel">
<button type="submit">SUBMIT</button>
</form>
`
})
new Vue({
el: '#app',
components: {
formGenerator
},
data: {
model: {},
schema: {
fields: [{
id: "dcno1",
label: "DC No.",
model: "dcno",
name: "dcno",
ref: "dcno",
className: "",
type: "input",
inputType: "text",
required: true,
order: 2
}]
}
}
})
<script src="https://unpkg.com/vue"></script>
<div id="app">
<form-generator :schema="schema" v-model="model"></form-generator>
<h2>Changing model</h2>
{{ model }}
</div>