NumberFrmate

mail@pastecode.io avatar
unknown
javascript
a month ago
4.2 kB
3
Indexable
Never
<template>
  <div class="mb-0 input-form" :class="divClass">
    <FormBaseLabel v-if="label" :label="label" :required="required" />

    <div class="phone_field">
      <input
        :id="id"
        :name="type"
        :type="type"
        v-model.trim="telNumber"
        @input="numberFormatting"
        @focus="focus"
        @keydown="keydownHandler"
        v-bind="$attrs"
        :placeholder="placeholder"
        class="form_input"
        :class="[errorMessage || error ? 'isWarning' : '', classes]"
        :style="{ paddingLeft: type === 'search' ? '40px' : '' }"
        :autocomplete="autocomplete"
        :disabled="disabled"
        :autofocus="autofocus"
        :required="required"
        :min="min"
        :max="maxNumberLength"
        ref="inputRef"
      />
    </div>
  </div>

  <transition name="fade-in">
    <p class="form_error_message" v-if="error">
      <Icon name="ri:error-warning-fill" />
      <span>{{ error }}</span>
    </p>
  </transition>
</template>

<script setup>
const props = defineProps({
  modelValue: {
    type: [String, Number],
    default: 0,
  },
  type: {
    type: String,
    default: 'tel', // Possible values: 'text', 'phone'
  },
  label: {
    type: String,
    default: '',
  },
  id: {
    type: String,
    default: '',
  },
  name: {
    type: String,
    default: '',
  },
  placeholder: {
    type: String,
    default: '019XXXXXXXX',
  },
  divClass: {
    type: String,
    default: '',
  },
  classes: {
    type: String,
    default: '',
  },
  required: {
    type: Boolean,
    default: false,
  },
  error: {
    type: String,
    default: '',
  },
  autocomplete: {
    type: String,
    default: 'off',
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  autofocus: {
    type: Boolean,
    default: false,
  },
  sanitizeInput: {
    type: Boolean,
    default: false,
  },
  min: {
    type: Number,
    default: null,
  },
  max: {
    type: Number,
    default: 11,
  },
});

const emit = defineEmits(['update:modelValue']);

const errorMessage = ref('');
const telNumber = ref('');
const maxNumberLength = ref(props.max);
const inputRef = ref(null);
const isError = ref(false);

let value = '';

// formate BD mobile & tel number
const formatPhone = (str) => {
  const digits = String(str)?.replace(/\D/g, '');

  if (/^02/.test(digits) && digits.length <= 9) {
    maxNumberLength.value = 9;
    isError.value = false;
    return `${digits.slice(0, 2)}-${digits.slice(2)}`;
  }

  if ((/^01/.test(digits) || /^09/.test(digits)) && digits.length <= 11) {
    maxNumberLength.value = 11;

    isError.value = false;
    return `${digits.slice(0, 5)}-${digits.slice(5)}`;
  }

  return '';
};

// remove hyphen
const keydownHandler = (e) => {
  if (e.key === 'Backspace' && telNumber.value.endsWith('-')) {
    e.preventDefault();
    telNumber.value = telNumber.value.slice(0, -1);
  }
};

const numberFormatting = (e) => {
  const formattedNumber = formatPhone(e.target.value);

  if (formattedNumber !== '') {
    telNumber.value = formattedNumber;

    value = formattedNumber;
  } else {
    e.target.value = telNumber.value;
    isError.value = true;
  }

  // prevent input if exceed maximum length
  if (telNumber.value.length >= maxNumberLength.value) {
    telNumber.value = value;
    e.preventDefault();
  }

  emit('update:modelValue', telNumber.value?.replace('-', ''));
};

const focus = () => {
  telNumber.value = telNumber.value;
};

watch(
  () => isError.value,
  (newVal, oldVal) => {
    if (newVal) {
      errorMessage.value = 'Please input a valid number';
    } else {
      errorMessage.value = '';
    }
  },
  { deep: true, immediate: true },
);

// set default value
watchEffect(() => {
  if (isEmpty(telNumber.value)) {
    telNumber.value = formatPhone(props.modelValue);
  }
});

const focusInput = () => {
  if (inputRef.value && inputRef.value.focus) {
    inputRef.value.focus();
  }
};

onMounted(() => {
  if (props.autofocus) {
    focusInput();
  }
});
</script>
Leave a Comment