Closed pravinfullstack closed 5 years ago
I also need that. Why did you close it?
+1
+1
@power-cut @koraykupe @andreladocruz @ITBDarky did you guys end up figuring out how to hook the two together?
@palfaro91 ... nops...
Enjoy.
<template>
<ValidationProvider
ref="provider"
:rules="rules"
:name="name"
v-slot="{ errors }"
>
<div :class="rootClass" ref="wrapper">
<div class="v-input__control">
<div class="v-input__slot">
<div class="v-text-field__slot">
<label :class="labelClass">
{{ name }}
</label>
<vue-tel-input
ref="phoneInput"
mode="international"
v-bind="attrs"
v-on="listeners"
></vue-tel-input>
</div>
</div>
<div class="v-text-field__details">
<div
v-if="errors.length"
class="v-messages theme--light error--text"
role="alert"
>
<div class="v-messages__wrapper">
<div class="v-messages__message">
{{ errors[0] }}
</div>
</div>
</div>
</div>
</div>
</div>
</ValidationProvider>
</template>
<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
import { ValidationProvider, extend } from 'vee-validate';
import { VueTelInput } from 'vue-tel-input';
const INSTANCES = new Map();
extend('phone', (_, params) => {
if (Array.isArray(params)) {
const validator = INSTANCES.get(Number(params[0]));
if (validator) {
const isValid = validator();
if (!isValid) {
return 'Please enter correct phone number, valid for the country selected';
}
return isValid;
}
}
return true;
});
@Component({
components: {
VueTelInput,
ValidationProvider
}
})
export default class APhoneInput extends Vue {
_uid!: number;
$refs!: {
provider: InstanceType<typeof ValidationProvider>;
phoneInput: InstanceType<typeof VueTelInput>;
wrapper: HTMLDivElement;
};
innerValue = '';
isFocused = false;
isOpen = false;
isInputValid = true;
maxWidth = 390;
get id() {
return this._uid;
}
get name() {
return this.$attrs.label;
}
get isValid() {
return this.innerValue
? this.isInputValid === true
: !this.$refs.provider?.errors.length;
}
get rules() {
return [this.$attrs.rules, `phone:${this.id}`]
.filter(Boolean)
.join('|');
}
get rootClass() {
const classes = [
'v-input-phone',
'v-input theme--light',
'v-text-field',
'v-text-field--filled',
'v-text-field--is-booted',
'v-text-field--enclosed'
];
if (this.isFocused) {
classes.push('v-input--is-focused', 'primary--text');
}
if (this.innerValue) {
classes.push('v-input--is-dirty', 'v-input--has-state');
}
if (this.isValid) {
classes.push('success--text');
} else {
classes.push('error--text');
}
return classes.join(' ');
}
get labelClass() {
const classes = new Set(['v-label', 'theme--light']);
if (this.isFocused || this.isOpen) {
classes.add('primary--text');
classes.add('v-label--active');
}
if (this.innerValue) {
classes.add('v-label--active');
}
if (this.isValid) {
classes.add('success--text');
} else {
classes.add('error--text');
}
return [...classes].join(' ');
}
get attrs() {
return {
defaultCountry: 'US',
preferredCountries: ['US', 'GB'],
dropdownOptions: {
width: `${this.maxWidth}px`,
showFlags: true,
showDialCodeInList: true,
//showDialCodeInSelection: true,
showSearchBox: true
},
inputOptions: {
placeholder: ''
},
...this.$attrs
};
}
get listeners() {
return {
focus: () => {
this.isFocused = true;
},
blur: () => {
this.isFocused = false;
},
open: () => {
this.isOpen = true;
setTimeout(this.focusSearchInput.bind(this), 50);
},
close: () => {
this.isOpen = false;
},
input: (value: string) => {
this.innerValue = value;
this.$emit('input', value);
},
validate: (data: { valid: boolean }) => {
this.isInputValid = data.valid;
}
};
}
created() {
INSTANCES.set(this.id, () => this.isValid);
}
beforeDestroy() {
INSTANCES.delete(this.id);
}
mounted() {
// inherit the width of the control
this.maxWidth = this.$refs.wrapper.clientWidth;
}
focusSearchInput() {
const list = this.$refs.phoneInput.$refs.list as HTMLDivElement;
const inputs = list.getElementsByClassName('vti__search_box');
if (inputs.length) {
(inputs[0] as HTMLInputElement).focus();
}
}
}
</script>
<style src="vue-tel-input/dist/vue-tel-input.css"></style>
<style lang="scss">
.v-input-phone {
&.v-text-field--filled .v-label {
top: 13px;
left: 0px;
right: auto;
position: absolute;
&.v-label--active {
top: 18px;
}
}
.vue-tel-input {
border: none;
width: calc(100% + 11px);
margin-left: -11px;
&:focus-within {
border: none;
box-shadow: none;
}
.vti__dropdown {
margin-top: 22px;
&.open,
&:hover {
background-color: transparent;
}
}
.vti__dropdown-list {
padding: 0;
.vti__search_box {
width: calc(100% - 20px);
margin: 10px;
padding: 3px 5px;
}
.vti__dropdown-item {
padding: 4px 7px;
&:focus,
&:focus-visible {
outline: none;
}
}
}
}
}
</style>
how to integrate with vee-validate 4?
@vodnicearv did you ever figure it out?
I want help regarding using this vue-tel-input with vee-validate