How to clear Autocomplete field using a button - vue.js

Know how do I understand the selection field of a v-autocomplete by assigning it to a button.
The memory is even cleared, but the selection field is still the selected item.
Can anyone help me in this case? Any solution?
<Autocomplete
#getItemSelecionado="receberAno"
:items="anos"
label="Ano"
placeholder="Selecione um ano"
/>
clear() {
this.anoSelecionado = "";
this.areaSelecionada = "";
this.instituicaoSelecionada = "";
this.tituloSelecionado = "";
this.orientadorSelecionado = "";
this.pesquisadorSelecionado = "";
this.filtros = {};
},
The Autocomplete used above is a component created from the v-autocomplete below:
<template>
<v-autocomplete
:label="label"
:placeholder="placeholder"
v-model="select"
:items="items"
:item-text="itemText"
:disabled="disable"
outlined
:multiple="multiple"
:chips="chips"
flat
filled
color="#277049"
clearable
>
</v-autocomplete>
</template>
<script>
export default {
name: "AutocompleteAtom",
props: {
color: {
type: String,
},
label: {
type: String,
},
placeholder: {
type: String,
},
items: {
type: Array,
},
itemText: {
type: String,
},
disable: {
type: Boolean,
},
multiple: {
type: Boolean,
},
chips: {
type: Boolean,
},
},
data: () => {
return {
select: null,
};
},

You assign the v-model to variable "select" in component data.
And the value of this input is storage only in this child component. You can pass it to parent component by #onChange event and $emit.
Documentation: https://vuejs.org/guide/components/events.html
You can also assign prop as a v-model and passing it from parent component.
For example:
<Autocomplete
#getItemSelecionado="receberAno"
:items="anos"
:value="value"
label="Ano"
placeholder="Selecione um ano"
/>

Related

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>

Quasar custom input component field validation

I am trying to create Quasar custom select component with autocomplete. Everything works fine except the validation error, the validation error is showing only when I click the input box and leave without adding any value. But, the form is submitting even there are any errors.
Component code
<q-select
ref="members"
v-model="sModel"
use-input
:options="filteredOptions"
:multiple="multiple"
:use-chips="useChips"
:label="label"
:option-label="optionLabel"
:option-value="optionValue"
#filter="filterFn"
#input="handleInput"
emit-value
map-options
hint
dense
outlined
lazy-rules
:rules="rules"
>
<template v-slot:prepend>
<q-icon :name="icon" />
</template>
</q-select>
</template>
<script>
export default {
props: {
value: Array,
rules: Array,
icon: String,
label: String,
optionValue: String,
optionLabel: String,
options: Array,
multiple: Boolean,
useChips: Boolean
},
data () {
return {
filteredOptions: this.options,
sModel: this.value,
validationErrors:{
}
}
},
methods: {
filterFn (val, update) {
if (val === '') {
update(() => {
this.filteredOptions = this.options
// with Quasar v1.7.4+
// here you have access to "ref" which
// is the Vue reference of the QSelect
})
return
}
update(() => {
const needle = val.toLowerCase()
const optionLabel = this.optionLabel
this.filteredOptions = this.options.filter(function(v){
// optionLabel
return v[optionLabel].toLowerCase().indexOf(needle) > -1
})
})
},
handleInput (e) {
this.$emit('input', this.sModel)
}
},
}
</script>
In the parent component, this is how I am implementing it,
<AdvancedSelect
ref="members"
v-model="members"
:options="extAuditEmployees"
icon="people_outline"
multiple
use-chips
label="Team Members *"
option-label="formatted_name"
option-value="id"
:rules="[ val => val && val.length && !validationErrors.members > 0 || validationErrors.members ? validationErrors.members : 'Please enter Team members' ]">
</AdvancedSelect>
Try adding this method on select component methods:
validate(...args) {
return this.$refs.members.validate(...args);
}
It worked for me, apparently it sends the validation of the input to the parent
Source consulted: https://github.com/quasarframework/quasar/issues/7305
add ref to the form and try to validate the form.
you can give give props "greedy" to the form.

Two way data binding with :model.sync when prop has get() and set()

I have a computed property that I use as v-model on an input. I've written it this way to get reactivity -- this calls my setText Vuex action which I then can get with my getter text. It looks like this:
text: {
get() {
return this.text;
},
set(value) {
this.setText(value);
},
},
and I use it in my input like this:
<input class="input" type="text" v-model="text" />
This works well. Now, I've put the input in question into a separate component which I use. This means I have to pass the text v-model as props, which I do with :model.sync, like so:
<myInput :model.sync="text"/>
and in the myInput component I use the props like so:
<input class="input" id="search-order" type="text" :value="model" #input="$emit('update:model', $event)">
But this doesn't seem to work at all, whenever I type into the input, the input says: [object InputEvent] and if I try to see and the value of model it's {isTrusted: true}. I'm assuming it's because of the getters and setters I have on my computed property. How do I pass these down to the child component?
Instead of using the .sync modifier you can support the v-model directive in your custom component. v-model is syntax sugar for a value prop and an input event.
To support v-model just make sure your custom component has a value prop and emits an input event with the new value: this.$emit('input', event.target.value).
Here is an example of a <BaseInput> component I use, it's written in TypeScript:
<template>
<input
:type="type"
:value="value"
class="input"
v-on="listeners"
>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({
name: 'BaseInput',
props: {
type: {
type: String,
default: 'text',
},
value: {
type: [String, Number],
default: '',
},
lazy: {
type: Boolean,
default: false,
},
number: {
type: Boolean,
default: false,
},
trim: {
type: Boolean,
default: false,
},
},
computed: {
modelEvent(): string {
return this.lazy ? 'change' : 'input'
},
parseModel(): (value: string) => string | number {
return (value: string) => {
if (this.type === 'number' || this.number) {
const res = Number.parseFloat(value)
// If the value cannot be parsed with parseFloat(),
// then the original value is returned.
return Number.isNaN(res) ? value : res
} else if (this.trim) {
return value.trim()
}
return value
}
},
listeners(): Record<string, Function | Function[]> {
return {
...this.$listeners,
[this.modelEvent]: (event: HTMLElementEvent<HTMLInputElement>) =>
this.$emit(this.modelEvent, this.parseModel(event.target.value)),
}
},
})
</script>
You can use it like so:
<BaseInput v-model="text" />

Browser was freeze when i update array items in v-for block

I use v-autocomplete component and updating items list after http request. But browser was freeze when i set items. What's wrong?
{
mixins: [search_field_block],
data: function () {
return {
item_component: {
props: ['item'],
template: '<div v-html="item.full_name"></div>'
}
};
},
methods: {
search: function (text) {
this.search_text = text.trim();
if (this.search_text) {
this.doGET('/api-method/search_place/', {'query': this.search_text}, this.update_items);
}
},
update_items: function (data) {
this.items = data;
}
}
}
I use a mixin for other components. It contained universal template with v-autocomplete:
<field-block :label="label" :error="field_error" :description="item_description">
<v-autocomplete slot="input"
class="page-form__field required"
:class="{ focused: focused, 'not-empty': not_empty, error: field_error != null, 'list-open': is_list_open }"
v-model="value"
ref="autocomplete"
:required="required"
:inputAttrs="{ref: 'input', autocomplete: 'off'}"
:items="items"
:component-item="item_component"
:get-label="getLabel"
:min-len="2"
#update-items="search"
#item-selected="onSelect"
#input="onInput"
#blur="onBlur"
#focus="onFocus">
</v-autocomplete>
</field-block>
I was find v-autocomplete on the github. It contain a v-for block for rendering search results
I found the problem. I have "computed" property and set value to parent app:
computed: {
is_list_open: function () {
this.$parent.list_opened = this.focused && this.items.length > 0 || (this.$refs.autocomplete ? this.$refs.autocomplete.show : false);
return this.$parent.list_opened;
}
},
This is incorrect behavior.

Vuejs updating field updating all fields

I have 2 formfields Title and Link, when typing a text into Title also link gets the same value.
Something goes wrong with updateValue method, this wil execute twice.
How can i achieve that both fields getting there own values?
App.vue
<form-input v-on:input="handleTitle" :label="'title'" :labelvalue="'Titel'" :type="'text'" :placeholder="''" :name="'title'" :value="title" :classname="'form-control'" :id="''"></form-input>
<form-input v-on:input="handleLink" :label="'Link'" :labelvalue="'Link'" :type="'text'" :placeholder="''" :name="'link'" :value="title" :classname="'form-control'" :id="''"></form-input>
data() {
return {
title: '',
link: '',
}
}
methods: {
handleTitle: function (evt) {
this.title = evt.target.value
},
handleLink: function (evt) {
this.link = evt.target.value
},
Template:
<input v-on:input="updateValue($event)" :type="type" :placeholder="placeholder" :name="name" :value="value" :class="classname" :id="id">
export default {
props: {
type: String,
placeholder: String,
name: String,
value: String,
classname: String,
id: String,
label: String,
labelvalue: String
},
methods: {
updateValue: function (evt) {
console.log(this.$emit('input', evt))
this.$emit('input', evt)
}
}
}
Your prop :value have the same variable in both <form-input :value="title"> change one to <form-input :value="link">