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

Error trying to use inputComponent #226

Closed
nandoofz opened this issue Jan 9, 2019 · 32 comments
Closed

Error trying to use inputComponent #226

nandoofz opened this issue Jan 9, 2019 · 32 comments

Comments

@nandoofz
Copy link

nandoofz commented Jan 9, 2019

Hi,

I'm trying to use the property inputComponent with the Input component from material-ui (https://material-ui.com/api/input/) but when I try to type something I get the error Uncaught TypeError: text.search is not a function and I'm not sure what is the problem. The documentation of this property is a little bit simple and I couldn't understand what else I would need to do.

        <PhoneInput
          name={name}
          country={defaultCountry}
          dictionary={dictionary}
          international={international}
          value={value}
          limitMaxLength={limitMaxLength}
          onChange={phone => this.handleOnChange(name, phone)}
          inputComponent={Input}
          // inputComponent={<Input />}
          // inputComponent={props => <Input {...props} />}
        />

image

catamphetamine pushed a commit that referenced this issue Jan 9, 2019
@catamphetamine
Copy link
Owner

Released [email protected] with a fix.

catamphetamine pushed a commit that referenced this issue Jan 10, 2019
@catamphetamine
Copy link
Owner

Actually, I reverted the fix.
Your bug is that you're passing an event to onChange instead of a string.

@NevenLiang
Copy link

NevenLiang commented Jul 14, 2019

In [email protected], I still met this problem.

屏幕快照 2019-07-14 下午7 26 08

I used the <TextField/> component of Material-UI as the custom input component in react-phone-number-input.

import TextField from 'material-ui/TextField';
import PhoneNumberInput from 'react-phone-number-input';

import 'react-phone-number-input/style.css';

<PhoneNumberInput
  country="US"
  style={inputStyle}
  placeholder="Phone Number"
  value={this.props.model.phoneNumber.value}
  onChange={this.props.handleChange}
  inputComponent={PhoneNumberTextField}
/>

...

function PhoneNumberTextField(props) {
  function handlePhoneChange(event) {
    console.log(event.target.value);
  }

  return (
    <TextField
      id="phoneNumber"
      floatingLabelText="Phone Number"
      value={props.value}
      style={inputStyle}
      onChange={props.onChange}
      // onChange={handlePhoneChange}
    />
  )
}

Another question

The inputComponent property seems only supporting type of React Component, not including React Element(JSX), inputComponent={<PhoneNumberTextField {...someProps}/>}.

How should I pass the props from <PhoneNumberInput/> to <PhoneNumberTextField/>? Like, onChange and others properties.

Could you provide a full example to show me how to use inputComponent property correctly in react-phone-number-input? Or an example to use custom input component.

Thx!

@catamphetamine
Copy link
Owner

@NevenLiang
See the solution of the issue: the input component must supply a string to onChange(), not an event.
Create a wrapper component for that.

Another question
The inputComponent property

The inputComponent property only accepts a component, not an element.
You're passing an element.

How should I pass the props

The readme states that "all other props are passed to input".

Could you provide a full example to show me how to use inputComponent property correctly in react-phone-number-input? Or an example to use custom input component.

There's one: the "smart" input (InputSmart.js).
But you don't need to look at it.

@NevenLiang
Copy link

NevenLiang commented Jul 14, 2019

@catamphetamine
Thanks for your answer!

  1. "all other props are passed to input", is the word input equal to input component, just the parameter for inputComponent props?

  2. The <PhoneNumberInput/> requires onChange props. So I should use props.onChange in <PhoneNumberTextField/> to get the callback passed to <PhoneNumberInput/> from <Form/>, which contains all the data and event handlers of the form, is that right?

@catamphetamine
Copy link
Owner

  1. Yes. See the source code.

The <PhoneNumberInput/> requires onChange props.

No, inputComponent requires onChange.
See the readme for more details.

@NevenLiang
Copy link

NevenLiang commented Jul 14, 2019

OK, but I am still a bit confused about the data communication between <PhoneNumberInput/> and <PhoneNumberTextField/>.

image

If I don't set onChange on <PhoneNumberInput/>, it will throw a warning. Is it fine to ignore?


I create a codesandbox example, would you mind helping to finish the confusing part for me?

Thank you very much!!

@catamphetamine
Copy link
Owner

@NevenLiang

If I don't set onChange on <PhoneNumberInput/>, it will throw a warning. Is it fine to ignore?

You must set onChange on <PhoneInput/> and the custom inputComponent must accept onChange as well.

@NevenLiang
Copy link

NevenLiang commented Jul 15, 2019

@catamphetamine

OK! I still have some questions:

  1. What are the differences between onChange callback of <PhoneInput/> and custom inputComponent? The two callback functions set to them should not be the same, right?

  2. If I set the custom inputComponent, what is the purpose of onChange callback for the <PhoneInput/>? And when will it be called?

I understand the purpose of onChange callback for the custom inputComponent, which will be called when the value of input component updates. I should pass the callback contains setState from data management component(parent component) to it.

@catamphetamine
Copy link
Owner

What are the differences between onChange callback of <PhoneInput/> and custom inputComponent? They should not be the same, right?

It's not clear what you mean.
Explain in more details.

If I set the custom inputComponent, what is the purpose of onChange callback for the <PhoneInput/>? And when will it be called?

onChange callback for the <PhoneInput/> is called whenever a user edits the phone number.
Before it's called the onChange callback for the inputComponent is called.
The inputComponent's onChange callback shouldn't be used to set state variables or something like that. The average user shouldn't even know that inputComponent exists.

@NevenLiang
Copy link

NevenLiang commented Jul 15, 2019

Please see the code sandbox .

I don't know how to trigger the onChange callback for the .

And the custom input component can't get the value of input.

These are the things confuses me.

@catamphetamine
Copy link
Owner

I can answer questions if you post them here.
I won't look into sandboxes though.

@NevenLiang
Copy link

import React from "react";
import PhoneNumber from "react-phone-number-input";
import TextField from "material-ui/TextField";
import MuiThemeProvider from "material-ui/styles/MuiThemeProvider";

import "react-phone-number-input/style.css";

class PhoneNumberInput extends React.Component {
  state = {
    number: ""
  };

  handleUpdate = number => {
    console.log('Something has been changed.');

    this.setState({
      number: number
    });
  };

  render() {
    const { number } = this.state;

    return (
      <div>
        <PhoneNumber
          country="US"
          placeholder="Phone Number"
          value={number}
          onChange={this.handleUpdate}
          inputComponent={PhoneNumberTextField}
        />
        <p>Input Value: {number}</p>
      </div>
    );
  }
}

const PhoneNumberTextField = props => {
  function handleTextFieldChange(value) {
    // The value is Synthetic Event Object
    // console.log(value);
    console.log('Input Update.');
    console.log('The value is: ');
    console.log(props.value);
    console.log('--------------')
  }

  return (
    <MuiThemeProvider>
      <TextField
        id="phoneNumber"
        floatingLabelText="Phone Number"
        onChange={handleTextFieldChange}
      />
    </MuiThemeProvider>
  );
};

export default PhoneNumberInput;

@catamphetamine
Copy link
Owner

What's not working?
See if this works.

const PhoneNumberTextField = ({ onChange, ...rest }) => {
  return (
    <MuiThemeProvider>
      <TextField
        {...rest}
        onChange={(event) => onChange(event.target.value)} />
    </MuiThemeProvider>
  );
};

@NevenLiang
Copy link

Yes, it works.

Thanks you very much!!


I am still a bit confused about this.

See the solution of the issue:
the input component must supply a string to onChange(), not an event.
Create a wrapper component for that.

onChange={(event) => onChange(event.target.value)}, does it mean I should pass the string value to the props.onChange from <PhoneInput/> as parameter, not the event object.

@catamphetamine
Copy link
Owner

onChange={(event) => onChange(event.target.value)}, does it mean I should pass the string value to the props.onChange from as parameter, not the event object.

Again, it's not clear what you mean.

@NevenLiang
Copy link

const PhoneNumberTextField = ({ onChange, ...rest }) => {
  return (
    <MuiThemeProvider>
      <TextField
        {...rest}
        onChange={(event) => onChange(event.target.value)} /> // <-- this line
    </MuiThemeProvider>
  );
};

In your code above, the type of parameter in props.onChange, which is from <PhoneInput/>, should be string, event.target.value, not the event object.

This is the onChange requirement of inputComponent talking about, right?

@catamphetamine
Copy link
Owner

catamphetamine commented Jul 15, 2019 via email

@NevenLiang
Copy link

Where the onChange's parameter type limit of inputComponent works?

Have I misunderstood the document?

@catamphetamine
Copy link
Owner

Where the onChange's parameter type limit of inputComponent works?

It's not clear what you mean.

@NevenLiang
Copy link

In docs, onChange(value : string) — Updates the value, does it have a relationship with your code onChange={(event) => onChange(event.target.value)} />?

Is it clear?

@catamphetamine
Copy link
Owner

Yes, it says:

inputComponent

Receives properties:

onChange(value : string) — Updates the value.

Don't you think this is true?

@NevenLiang
Copy link

In your code above, the type of parameter in props.onChange, which is from <PhoneInput/>, should be string, event.target.value, not the event object.

This is the onChange requirement of inputComponent talking about.

This is what I mean.

If the type of parameter passed to props.onChange is not string,
the error will be thrown: Uncaught TypeError: text.search is not a function.

I think I understand it correctly.

Thanks for your patience in answering lots of question of mine, ❤️.

@catamphetamine
Copy link
Owner

If the type of parameter passed to props.onChange is not string,
the error will be thrown: Uncaught TypeError: text.search is not a function.

No.
If the type of parameter passed to inputComponent's onChange property is not string,
the error will be thrown: Uncaught TypeError: text.search is not a function.

@NevenLiang
Copy link

const PhoneNumberTextField = ({ onChange, ...rest }) => {
  return (
    <MuiThemeProvider>
      <TextField
        {...rest}
        onChange={(event) => onChange(event.target.value)} /> // <-- this line
    </MuiThemeProvider>
  );
};

But at the line of code, inputComponent's onChange property accept event object as parameter, the props.onChange from <PhoneInput/> accept event.target.value string as parameter.

How to explain them?

@catamphetamine
Copy link
Owner

But at the line of code, inputComponent's onChange property accept event object as parameter.

No, it doesn't.
It's event.target.value, not event.

@NevenLiang
Copy link

NevenLiang commented Jul 15, 2019

But in the code onChange(event.target.value), onChange is the props.onChange from <PhoneInput/>.

Is the description in document not very accurate?

Using the parameter passed to props.onChange from <PhoneInput/> must be a string, it may be more accurate.

I suggest that you add some example like this, to the github page of this project.

import React from 'react';
import TextField from 'material-ui/TextField';
import PhoneNumberInput from 'react-phone-number-input';

import 'react-phone-number-input/style.css';

<PhoneNumberInput
  country="US"
  placeholder="Phone Number"
  value={this.props.model.phoneNumber.value}
  onChange={this.props.handleChange}
  inputComponent={PhoneNumberTextField}
/>

...

class PhoneNumberTextField extends React.Component {
  setRef = ref => {
    this.input = ref;
  };

  focus = () => {
    this.input.focus();
  };

  render() {
    // just extract `country` and `metadata` out of `props`,
    // not passing to the input component
    const {country, metadata, onChange, ...rest } = this.props;

    return (
      <TextField
        {...rest}
        id="phoneNumber"  // not necessary
        floatingLabelText="Phone Number"  // not necessary
        ref={this.setRef}
        // `props.onChange` only accept string
        onChange={event => onChange(event.target.value)}  
      />
    )
  }
}

@catamphetamine
Copy link
Owner

But in the code onChange(event.target.value), onChange is the props.onChange from <PhoneInput/>.

No, it's not.
It's another onChange() function created inside <PhoneInput/>.

@TylerRick
Copy link

Awesome, thanks, @NevenLiang, for getting me on the right track. Your adapter component is a good start.

I've fixed a couple issues with it:

  • ref should be inputRef in order for focus to actually work,
  • floatingLabelText doesn't exist in current material-ui version; assuming it's just label now

I've posted my version here if interested: https://codesandbox.io/s/integrate-react-phone-number-input-with-material-uicore-ohfwp

@TylerRick
Copy link

TylerRick commented Sep 25, 2019

@NevenLiang, did you ever develop this further?

It looks like if you supply your own inputComponent, then your input component is responsible for formatting the phone number value, too. Did you happen to add that feature to yours?

I was hoping that using a custom inputComponent would only change which input was used (mostly to make the look consistent with the other inputs in the form) but everything else would work the same.

Automatic formatting of the phone number seems like something react-phone-number-input could/should do for you regardless of which inputComponent you happen to be using. I wish that functionality were exposed buried within InputBasic. (I wonder if that was necessary due to differences between InputBasic and InputSmart?)

@TylerRick
Copy link

I managed to get phone number formatting working with Material UI Input. See #283.

@catamphetamine
Copy link
Owner

catamphetamine commented Oct 16, 2019

@TylerRick

It looks like if you supply your own inputComponent, then your input component is responsible for formatting the phone number value, too.

Yes, it is (for some reason).
Maybe it shouldn't.
I guess it's for historical reasons: the two input components ("basic" and "smart") use completely different methods for formatting the value.

I was hoping that using a custom inputComponent would only change which input was used (mostly to make the look consistent with the other inputs in the form) but everything else would work the same.

I guess your point here is a valid one.
I've added a new property called numberInputComponent: bc7480c
(will be released today)
It's "input" by default and could be set to a Material UI input or something like that.
And its onChange() function receives an event now (event.target.value should be the new value).

Update: Released [email protected] with the numberInputComponent property.

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