Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

input ref? #366

Open
stoplion opened this issue Feb 19, 2021 · 3 comments
Open

input ref? #366

stoplion opened this issue Feb 19, 2021 · 3 comments

Comments

@stoplion
Copy link

Is there a way to get a ref of the input?

@goelshobhit
Copy link

Import { useRef } from 'React';

const phoneNoRef = useRef();

return (
<IntlTelInput
ref={phoneNoRef}
.....
onSelectFlag={() => {
const { current } = phoneNoRef;
}}
/>

@justin-calleja
Copy link

justin-calleja commented Mar 4, 2021

I'm not sure if you can do what @goelshobhit suggests but I might be wrong. I have checked master branch for ref prop on IntlTelInput. No hits. The TelInput rendered by the main export of the package (IntlTelInput) does take a ref but I see no way of getting to it and if you could, you'd be overwriting what the package itself passes to it.

Here's what I'm doing (using v4.3.4 of react-intl-tel-input which has the same limitation):

TLDR; useRef on wrapper element and then on mount, query for input element and assign to a second ref you use just for storing the input.

const InputPhone = ({ autoFocus, field, onKeyDown, onPhoneNumberChange, onSelectFlag }: InputPhoneProps) => {
  // NOTE: all this getting of input el to add a blur event listener to it is to
  // remove the error / success message on blur of input (after user re-selects input after submit).
  // Submit (enter key down on input or press of button) will auto blur input without removing messages.
  // If this is not required, remove this code:
  const containerRef: MutableRefObject<null | HTMLDivElement> = useRef(null);
  const inputRef: MutableRefObject<null | HTMLInputElement> = useRef(null);
  useEffect(() => {
    const inputEl = containerRef.current?.getElementsByTagName('input')?.[0];
    if (!inputEl) {
      throw new Error(`Could not find the phone input element with name ${fieldName}`);
    }
    inputRef.current = inputEl;
    inputRef.current.addEventListener('blur', field.onBlur);

    return () => {
      if (inputRef.current && field.onBlur) {
        inputRef.current.removeEventListener('blur', field.onBlur);
      }
    };
  }, []);

  return (
    <div ref={containerRef}>
      <CPInputPhone
        autoFocus={autoFocus}
        fieldName={field.name ?? fieldName}
        onPhoneNumberChange={onPhoneNumberChange}
        onSelectFlag={onSelectFlag}
        // Pass onKeyDown to telInputProps because these get passed to <input> element
        // rendered by react-intl-tel-input.
        // onPhoneNumberChange does not get an event to work with. <input>'s onKeyDown does
        // so you can detect enter press:
        // NOTE: since react-intl-tel-input overwrites onChange and onBlur, passing them to
        // telInputProps is useless. onKeyDown is not overwritten.
        // https://github.com/patw0929/react-intl-tel-input/blob/v4.3.4/src/components/TelInput.js#L7-L22
        telInputProps={{ onKeyDown }}
      />
    </div>
  );
};

CPInputPhone is just a wrapper for IntlTelInput with some class names.

Edit:

Also note that if you're planning on adding some event listeners (like above) and you're working with useState... you're gonna have to wrap that in a useRef too otherwise you'll never get past the initial value of useState. See: https://stackoverflow.com/a/55265764/990159

const [error, setError] = useState(undefined)
field.onBlur = (e) => {
  // error will always be `undefined` here.
  if (error !== undefined) {
    setError(undefined);
  }
}

// Fix:
const [error, setError] = useState(undefined)
const errorRef = useRef(error);
const setErrorRef = (err) => {
    // keep new value of error after rerender:
    errorRef.current = err;
    // trigger rerender if necessary:
    setError(err);
};
field.onBlur = (e) => {
  if (errorRef.current !== undefined) {
    setErrorRef(undefined);
  }
}

@andrewsantarin
Copy link
Contributor

andrewsantarin commented Aug 7, 2021

@stoplion @goelshobhit @justin-calleja yes, there is one.

import React, { useEffect, useRef, useState } from 'react';
import IntlTelInput from 'react-intl-tel-input';

function App() {
  const intlTelInputRef = useRef<IntlTelInput | null>(null);

  useEffect(() => {
    intlTelInputRef.current?.tel?.focus();
  }, []);

  return (
    <div className="App">
      <IntlTelInput ref={intlTelInputRef} />
    </div>
  );
}

The intlTelInputRef has a property called tel which returns you the <input> HTML element. If you're looking for the TelInput React instance child, then I'm afraid that's not in the API yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants