I'm using vue-js and element-ui running on dev-server coming from vue-cli with the webpack template.
I'm trying to debounce the search value of a filterable input. In other words, I would like to debounce the :filter-method and getting the parameters query to do an ajax call
Here is the fiddle example https://jsfiddle.net/ffeohmk4/
In that example there is no debounce yet.
Problem
The function getFinalList is never triggered. I would assume since it is a computed propertyit should be triggered each time this.searchValue changes.
var Main = {
data() {
return {
searchValue : '',
filteredOptions : [],
options: [{
value: 'A',
label: 'A'
}, {
value: 'B',
label: 'B'
}, {
value: 'C',
label: 'C'
}, {
value: 'D',
label: 'D'
}, {
value: 'E',
label: 'E'
}],
value8: ''
}
},
computed : {
getFinalList () {
alert('getFinalList is called');
this.filteredOptions = this.options.filter(option => {
return option.value.toLowerCase().indexOf(this.searchValue.toLowerCase()) > -1;
})
}
},
methods : {
setSearchInput (query) {this.searchValue = query}
},
created () {
this.filteredOptions = this.options;
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
Here is a working another example https://jsfiddle.net/ffeohmk4/2/
getFinalList () {
return this.filteredOptions = this.options.filter(option => {
return option.value.toLowerCase().indexOf(this.searchValue.toLowerCase()) > -1;
})
}
<el-select v-model="searchValue" filterable placeholder="Select" :filter-method="setSearchInput">
<el-option v-for="item in getFinalList" :key="item.value" :label="item.label" :value="item.value">
</el-option>
Related
I got three VUE components with a structure like this:
Table->Modal->Form. When user selects a record, the modal will be triggered and shown.
The Form component contains a computed method method1 for computing a property that is not stored by the database. I want to add a column in the Table component and display the return value of method1 for each record.
So something like this:
Vue.component('Form`, {
computed: {
method1: function() {
// ...some calculations
// No parameter cuz Form contains the selected record's data model
return a_calculated_value
}
}
}
And I want to call method1 on each of the records in Table
In addition, if possible I do not want to store this calculated value in the database.
Is this possible?
look at my example maybe it can help
<template>
<marker-table
ref="dt"
v-model="showTable"
:raw-table-data="tableData"
/>
<v-btn #click="showGasTable">
Show GAS Table
</v-btn>
<v-btn #click="shoeElecTable">
Show Electricity Table
</v-btn>
</template>
<script>
import markerTable from './components/markerTable.vue'
methods:{
showGasTable () {
this.tableData = this.gas
this.$refs.dt.popHeaders('gas')
},
showElecTable () {
this.tableData = this.elec
this.$refs.dt.popHeaders('electricity')
},
}
</script>
Component markerTable.vue
<template>
<v-data-table
:headers="headers"
:items="tableData"
>
</v-data-table>
</template>
<script>
export default { // eslint-disable-next-line
props: ['rawTableData'],
data () {
return {
headers: [],
title: '',
rawData: '',
tableData: ''
}
},
computed: {
dataUpdate () {
this.rawData = this.rawTableData
return this.rawData
}
},
methods: {
popHeaders (value) {
if (value === 'gas') {
this.headers =
[{ text: 'Volume', value: 'Vm' },
{ text: 'Day', value: 'day' }]
this.title = 'GAS Supply'
} else if (value === 'electricity') {
this.headers =
[{ text: 'Units', value: 'units' },
{ text: 'Watts', value: 'watt' },
{ text: 'Time', value: 'time' }]
this.title = 'Electric Supply'
}
}
}
You can access the method popHeader from the child component with sets of data and can process them in your child and it will be returned to your main page.
I;m new on Vuejs and I'm currently working with composition API so I have an array like this:
const tabs = ref([
{
id: 1,
pdf: 'name1',
...
},
{
id: 2,
pdf: 'name2',
...
},
{
id: 3,
pdf: 'name3',
...
},
])
Then I have a div like this:
<div
v-for="tab in tabs"
:key="tab.name"
:href="tab.href"
class="px-12 pt-8 flex flex-col"
:class="[tab.current || 'hidden']"
#click="changeTab(tab)"
>
<div v-if="pdf != ''">
<div class="pt-4 font-bold underline">
<a :href="pdfSrc" target="_blank">See PDF</a>
</div>
</div>
</div>
And then I use computed to get current href value as:
props: {
tabs: {
type: Array as PropType<Array<any>>,
required: true,
},
},
computed: {
pdfSrc(): string {
return `/img/modal/pdf/${encodeURIComponent(this.tabs[0].pdf)}.pdf`
},
}
As you can see I always use tabs[0] so pdf value is always value name1 and I want to get depending of the selected tab
The tab method:
setup(props) {
const changeTab = (selectedTab: { id: number }) => {
props.tabs?.map((t) => {
t.id === selectedTab.id ? (t.current = true) : (t.current = false)
})
}
return {
changeTab,
}
},
How can I change static index 0 to dynamic one depending on the current tab?
I would suggest creating a new variable for tracking the selected tab.
const selectedTabId = ref(0);
Similar to tabs, this could be passed down in array and the value updated in changeTab function.
props: {
tabs: {
type: Array as PropType<Array<any>>,
required: true,
},
selectedTabId: {
type: Number
}
},
setup(props) {
const changeTab = (selectedTab: { id: number }) => {
selectedTabId = selectedTab.id
props.tabs?.map((t) => {
t.id === selectedTab.id ? (t.current = true) : (t.current = false)
})
}
return {
changeTab,
}
},
Finally in the computed use selectedTabId
computed: {
pdfSrc(): string {
return `/img/modal/pdf/${encodeURIComponent(this.tabs[this.selectedTabId].pdf)}.pdf`
},
}
I have a dynamic form where the v-model of the input control is resolved at runtime. It works for simple 0 or 1 level deep objects. But I do not know how to get it working for nested properties that are more than 1 level deep.
My HTML is like:
<div v-for="element in elements" v-bind:key="element.name">
<q-input v-model="inputdata[element.model]"></q-input>
</div>
Javascript
<script>
export default {
data () {
return {
inputdata: {
account: {
name: '',
address: {
street: ''
}
},
},
}
},
}
</script>
Array with data:
elements: [
{
type: 'text',
hint: 'Address',
label: 'Street',
model: 'account.address.street', // does not work. i want to be able to set any level deep property
name: 'street'
}
]
As long as I try to set the property at 0 or 1st level (inputdata or inputdata.account), it works.
How to get a property as deep as inputdata.account.name or inputdata.account.address.street to work?
maybe you can use custom iterative methods instead of v-model
const getValueByModel = (model, data) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
return getValueByModel(model.join('.'), data[key]);
}
else{
return data[model];
}
}
const setValueByModel = (model, oldObject, newValue) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
oldObject[key] = setValueByModel(model.join('.'), oldObject[key], newValue);
}
else{
oldObject[model] = newValue;
}
return oldObject;
}
const getValueByModel = (model, data) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
return getValueByModel(model.join('.'), data[key]);
}
else{
return data[model];
}
}
const setValueByModel = (model, oldObject, newValue) => {
if(model.includes('.')){
model = model.split('.');
let key = model.shift();
oldObject[key] = setValueByModel(model.join('.'), oldObject[key], newValue);
}
else{
oldObject[model] = newValue;
}
return oldObject;
}
new Vue({
el: '#app',
data () {
return {
inputdata: {
account: {
name: '',
address: {
street: ''
}
},
},
elements: [
{
type: 'text',
hint: 'Name',
label: 'Name',
model: 'account.name',
name: 'name'
},
{
type: 'text',
hint: 'Address',
label: 'Street',
model: 'account.address.street',
name: 'street'
},
]
}
},
methods: {
getInputValue(model){
return getValueByModel(model, this.inputdata);
},
updateInputValue(model, event){
let newValue = event.target.value;
this.inputdata = {...setValueByModel(model, this.inputdata, newValue)};
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<main id="app">
<div v-for="element in elements" v-bind:key="element.name">
<input :value="getInputValue(element.model)"
#input="updateInputValue(element.model, $event)"
:placeholder="element.name"/>
</div>
{{ inputdata }}
</main>
I have a simple Combobox component
And I want it to hide the menu part when the input is empty (so when a match is not found).
And to show it again when the match is found.
I wan unable to find anything in props of combobox and menu in the docs.
Any help will be appreciated.
<v-combobox
v-model="select"
:items="states"
:search-input.sync="search"
label="Select a favorite activity or create a new one"
></v-combobox>
new Vue({
el: '#app',
data () {
return {
select: 'Any value',
search: null,
items: [],
states: [
'Alabama',
'Alaska',
'American Samoa',
'Arizona',
'Arkansas',
'California',
'Colorado',
]
}
},
watch: {
search (val) {
if(val && val !== this.select) {
this.querySelections(val)
} else {
console.log(val)
}
}
},
methods: {
querySelections (v) {
// Simulated ajax query
setTimeout(() => {
this.items = this.states.filter(e => {
return (e || '').toLowerCase().indexOf((v || '').toLowerCase()) > -1
})
}, 500)
}
}
})
UPDATE
I think I found the solution
I added :menu-props="{value: autoselectMenu}" to the combobox then I created autoselectMenu: false property in my data. And in my watcher I did this
search (val) {
if(val && val !== this.select) {
this.querySelections(val)
this.autoselectMenu = true
} else if(!val) {
this.autoselectMenu = false
}
}
Link
You can pass custom value of value prop in menu-props attribute, so just set it to false when your search is empty, and don't pass it so it preserves default behaviour:
<v-combobox :menu-props="menuProps"
// ...
computed: {
menuProps() {
return !this.search ? {value: false} : {}
}
},
EDIT
One line:
<v-combobox :menu-props="{ ...(!search && {value:false}) }"
In my AgGrid data, I have a column which has a value of array of objects like this:
...
media:
[
{ title: 'Facebook', site: 'http://www.facebook.com'},
{ title: 'Twitter', site: 'http://www.twitter.com'}
{ title: 'Instagram', site: 'http://www.instagram.com'}
]
...
I managed to show in by cellRenderer like this
'Facebook, Twitter, Instagram'
But my problem is my floating filter , I don't know how to filter all columns which has for example has 'Facebook' media.
Here's my custom floating filter component:
import Vue from 'vue'
export default Vue.extend({
template: `
<input type="text" #change="valueChanged($event)"/>
`,
data: function() {
return {
currentValue: ''
}
},
beforeMount() {},
mounted() {},
methods: {
valueChanged(event) {
this.currentValue = event.target.value
this.params.onFloatingFilterChanged({
model: this.buildModel()
})
},
onParentModelChanged(parentModel) {
this.currentValue = !parentModel ? 0 : parentModel.filter
},
buildModel() {
if (this.currentValue === 0) {
return null
}
return {
filterType: 'text',
type: 'equalsTo',
filter: this.currentValue,
filterTo: null
}
}
}
});