iamstevendao / vue-tel-input

International Telephone Input with Vue
https://iamstevendao.com/vue-tel-input/
MIT License
814 stars 341 forks source link

Country list dropdown does not show #147

Open jAlfredsson opened 5 years ago

jAlfredsson commented 5 years ago

I can't get the drop down to show for some reason.. it keeps its style="display:none" when clicking..

I wrapped it in a component - parent: <base-form-tel-input :label="at('form.shipping.labelPhone')" type="tel" :value="address && address.phone" :defaultCountry="address && address.country && address.country.id" @input="addressForm.phone = $event.number.e164" @validityChange="validPhone = $event.isValid" :errors="!validPhone ? addressForm.getErrorMessagesForProperty('phone') : []" optional />

and the base-form-tel-input: <vue-tel-input :value="value" v-bind="$attrs" :defaultCountry="defaultCountry" disabledFetchingCountry wrapperClasses="telinput" inputClasses="input_field" dynamicPlaceholder @input="phoneCheck" @validate="$emit('validityChange', $event)" />

and the css for the classes i'm sending: `.telinput { padding: 6px 8px; margin-top: 4px; font-size: 20px; width: 100%; background: $color-input; border: 2px solid black; }

/deep/ .input_field { background: $color-input; font-size: 20px; width: 100%; }`

What am I missing?

jAlfredsson commented 4 years ago

Update: it seems as clicking the dropdown fires both the @open and @close-event right after another.. Is this expected behaviour? I'm kind of new to Vue, currently trying to find some pretty "hacky" way to stop the event chain once the @open is fired, but it doesn't feel as that should be the right way to do it..

iamstevendao commented 4 years ago

@jAlfredsson, It sounds really strange! Are there any ways I can reproduce the issue?

jAlfredsson commented 4 years ago

@iamstevendao I will see if I can cook something up .. however I just recognized I'm registering the vue-tel-input in my component rather than the global Vue instance, as I'd prefer doing it.. I'm a bit new to Vue, when I tried set it up in a JSFiddle it works as expected..

My awful hack to make it work looks like this:

private onDropdownOpen(){
    this.showDropdown = !this.showDropdown;
  }

  private onDropdownClose(){
    const el = this.$children[0].$refs.list as HTMLElement;
    this.$nextTick(() => {
         el.style.display = (this.showDropdown ? 'block' : 'none')
    })
  }

Here's my complete "BaseFormTelInput.vue" component:

<template>
  <label class="base-form-input">
    <span class="base-form-input__label">
      {{ label }}
      <span v-if="optional" class="base-form-input__flag">* optional</span>
    </span>
    <ul class="base-form-input__errors" v-if="errors.length > 0">
      <li class="error" v-for="(error, index) in errors" :key="index">{{ error }}</li>
    </ul>
    <vue-tel-input
      :value="value"
      v-bind="$attrs"
      :defaultCountry="defaultCountry"
      :disabledFetchingCountry="!!defaultCountry"
      wrapperClasses="telinput"
      inputClasses="input_field"
      dynamicPlaceholder
      @input="phoneCheck"
      @validate="$emit('validityChange', $event)"
      @open="onDropdownOpen"
      @close="onDropdownClose"
    />
  </label>
</template>

<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';
import { VueTelInput, VueTelInputResponse } from 'vue-tel-input';

@Component({ components: { VueTelInput } })
export default class BaseFormTelInput extends Vue {
  @Prop({ required: true })
  public label!: string;

  @Prop({ type: Boolean, default: false })
  public optional!: boolean;

  @Prop({ type: Array, default: () => [] })
  public errors!: string[];

  @Prop()
  public value?: any;

  @Prop()
  public defaultCountry?: string;

  showDropdown = false;

  private onDropdownOpen(){
    this.showDropdown = !this.showDropdown;
  }

  private onDropdownClose(){
    const el = this.$children[0].$refs.list as HTMLElement;
    this.$nextTick(() => {
         el.style.display = (this.showDropdown ? 'block' : 'none')
    })
  }

  private phoneCheck(num: string, obj: VueTelInputResponse) {
    this.$emit('input', obj);
    if (!num.length) {
      this.$emit('validityChange', { isValid: true });
    }
  }
}
</script>

<style lang="scss" scoped>
.base-form-input {
  margin: 8px 0;
  transition: 0.1s;
  &:hover {
    color: $color-theme-yellow;
  }
  &__label {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
  }
  &__flag {
    font-size: 18px;
    color: black !important;
  }
  &__errors {
    font-size: 16px;
    color: $color-theme-red;
    .error {
      margin: 4px 0;
    }
  }
  .telinput {
    padding: 6px 8px;
    margin-top: 4px;
    font-size: 20px;
    width: 100%;
    background: $color-input;
    border: 2px solid black;
  }

  /deep/ .input_field {
    background: $color-input;
    font-size: 20px;
    width: 100%;
  }

}
</style>

I will see if I can reproduce in a fiddle... but there's gotta be something I'm just doing wrong.

jpiros commented 4 years ago

I had the same issue. This happens when it is wrapped with a parent <label> element.

ByScripts commented 4 years ago

Same problem when the input is wrapped in a label.

Here is my hacky workaround:

<template>
  <vue-tel-input
    :class="{ 'vti_hack': vti_hack > 0 }"
    @open="!vti_hack && (vti_hack = 2)"
    @close="vti_hack -= 1"
  />
</template>

<script>
data() {
  return {
    vti_hack: 0,
  }
}
</script>

<style scoped>
.vti_hack::v-deep .vti__dropdown-list {
  display: block !important;
}
</style>
Pothecary commented 2 years ago

@iamstevendao Is there a planned fix for this?

Edit: I've noticed that if dropdownOptions.showSearchBox is set to true then the drop down works 🤔