Home > Mobile >  How to access child prop ref with vue 3 and Element Plus ui lib
How to access child prop ref with vue 3 and Element Plus ui lib

Time:10-05

I have a ref on a dropdown component called 'dropdown'

when an item is selected, I want to get the selected label(I can get the value, but its different than the label)

when I do dropdown.value I get an object where I can see the key with its value I want within it, which is 'selectedLabel'

if I do dropdown.value.selectedLabel I get blank and dropdown.value.selectedLabel.value is undefined.

enter image description here

<template>
  <div class="dropdown-component">
    <div class="label">{{name}}</div>
    <div class="select-container">
      <el-select
        ref="dropdown"
        v-model="selectedValue"
        filterable
        @change="$emit('OPTION_SELECTED', selectedOptionData())"
        :placeholder="placeholderText"
      >
        <el-option
          v-for="(item,index) in options"
          :key="index"
          :label="getLabel(item)"
          :value="getValue(item)"
        >
        </el-option>
      </el-select>
    </div>
  </div>
</template>

<script>
import { ref, defineComponent, watchEffect, computed } from 'vue'
import { getAPIObjFor } from '@/lib/ymm/YMMApi'

export default defineComponent({
  props: {
    labelKey: String,
    valueKey: { type: String, default: '' },
    name: String,
    next: String,
    groupState: Object
  },

  emits: ['OPTION_SELECTED'],

  setup (props) {
    console.log('Initing Dropdown-', props.name)

    const options = ref([])
    const selectedValue = ref('')
    const activeQueryParam = ref('')
    const dropdown = ref(null)
    const apiQueryObj = getAPIObjFor(props.name)

    const getOptionData = async ({ apiQuery, apiRequest }) => {
      // keep log
      console.log('%c'   props.name   ' query:', 'color:orange', apiQuery)
      activeQueryParam.value = apiQuery
      options.value = await apiRequest(apiQuery)
    }

    const getLabel = (_item) => {
      return _item[props.labelKey]
    }

    const getValue = (_item) => {
      const valueKey = props.valueKey === '' ? props.labelKey : props.valueKey
      return { value: _item[valueKey], label: getLabel(_item), x: 'x' }
    }

    const selectedOptionData = () => {
      // eslint-disable-next-line dot-notation
      // eslint-disable-next-line vue/no-ref-as-operand
      // eslint-disable-next-line
      console.log('selected dropdown', dropdown.value, dropdown.value.clearIcon, dropdown.value.selectedLabel)
      const { name } = props
      const { value, label } = selectedValue.value
      const selectedData = {
        [`${name}`]: {
          value,
          label,
          next: props.next
        }
      }
      return selectedData
    }

    const placeholderText = computed(() => {
      return `Select a ${props.name}`
    })

    watchEffect(() => {
      const query = apiQueryObj(props.groupState)
      if (query && query.apiQuery !== activeQueryParam.value) {
        selectedValue.value = ''
        getOptionData(query)
      }
    })

    return { options, getValue, getLabel, selectedValue, selectedOptionData, placeholderText, dropdown }
  }
})
</script>

<style lang="scss" scoped>

.dropdown-component {
  max-width: 500px;
  display: flex;
  flex-direction: row;
  justify-content: space-between;

  .select-container {
    max-width: 400px;
    display: flex;
    min-width: 20px;
    flex-grow: 1;
  }

  .el-select {
    width: 100%;
  }
}

</style>

CodePudding user response:

You can use el-select's selected property instead of selectedLabel, which always seems to be blank for some reason.

The selected property contains an array of selected options (each containing a currentLabel property), where the last array element is the most recently selected. However, the selected property is updated after the change event, so you have to await the next tick before accessing it.

import { nextTick } from 'vue'
//...

const selectedOptionData = async () => {
  await nextTick()
  const selected = dropdown.value.selected.at(-1).currentLabel
  console.log('selectedLabel', selected)
  //...
}

Also your @change event handler would have to be modified to be async for this to work:

<el-select @change="onChange">
export default {
  setup(props, { emit }) {
    const onChange = async () => {
      emit('OPTION_SELECTED', await selectedOptionData())
    }

    return { onChange }
  }
}

demo

Just be aware that the change-event also occurs when a tag is removed.

  • Related