RobinHerbots / Inputmask

Input Mask plugin
https://robinherbots.github.io/Inputmask/
MIT License
6.4k stars 2.17k forks source link

React onChange event doesn't work with Inputmask #1377

Closed nicholasrq closed 7 years ago

nicholasrq commented 8 years ago

There's the issue.

When attaching Inputmask to event inside of react component there is no way to know when value has been changed.

React uses input event to implement its onChange, so now there is now way to listen input when Inputmask attached. Also it does not matter when i attaching event handler (before or after Inputmask), input event will never fire.

And yes, there is no other way to handle input changes if i want to sync value with component state.

There is an example of how does it behave: http://codepen.io/nicholasrq/pen/kkaEoL?editors=0010

UPD: I've added a button to enable/disable masking to ensure that native behaviour works when no mask attached.

Also code example:

class Input extends React.Component{
  constructor(props){
    super(props)

    this.state = {
      mask: true
    }

    this.onChange = this.onChange.bind(this)
    this.toggleMask = this.toggleMask.bind(this)
  }

  render(){
    // attaching onChange in react-way
    // no luck
    return (
      <div>
        <input onChange={this.onChange} ref="input" placeholder="input" type="text"/>
        <button onClick={this.toggleMask}>{this.state.mask ? 'disable' : 'enable'}</button>
      </div>
    )
  }

  componentDidMount(){
    // this callback will be invoked right after
    // the component is completely rendered

    // let's take reference to input
    const input = this.refs.input

    // now let's try to add native event
    // handler BEFORE masking. not working
    input.addEventListener('input', this.onChange, false)

    // attaching inputmask
    this.attachMask()

    // also will not work
    input.addEventListener('input', this.onChange, false)
  }

  componentDidUpdate(prevProps, prevState){
    if(prevState.mask != this.state.mask){
      if(this.state.mask){
        this.attachMask()
      } else {
        this.mask.remove(this.refs.input)
      }
    }
  }

  attachMask(){
    const mask = new Inputmask({ mask: '99.99.99' })
    this.mask = mask.mask(this.refs.input)
  }

  onChange(e){
    console.log(e.target.value)
  }

  toggleMask(){
    this.setState({mask: !this.state.mask})
  }
}

console.clear();
ReactDOM.render(<Input/>, document.querySelector('#wrapper'))
RobinHerbots commented 8 years ago

Try the inputmask with the vanilla dependencylib instead of jquery. The input and chance event are synthetic. Event triggered by jquery don't trigger native events.

Op vr 2 sep. 2016 15:25 schreef Nicholas notifications@github.com:

Ther's the issue.

When attaching inputmask to event inside of react component there is no way to know when value has been changed.

React uses input event to implement its onChange, so now there is now way to listen input when inputmask attached. Also it does not matter when i attaching event handler (before or after inputmask), input event will never fire.

And yes, there is no other way to handle input changes if i want to sync value with component state.

There is an example of how does it behave: http://codepen.io/nicholasrq/pen/kkaEoL?editors=0010

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/RobinHerbots/jquery.inputmask/issues/1377, or mute the thread https://github.com/notifications/unsubscribe-auth/AATb74oHGlXdQr2mwVNv8s3gGO4D6XPsks5qmCPcgaJpZM4JztE3 .

nicholasrq commented 8 years ago

@RobinHerbots worked like a charm with vanilla dependencyLib. Great thanks.

One more question: can i use vanilla dependency if there is jQuery already loaded on the page?

RobinHerbots commented 8 years ago

@nicholasrq ,

Yep., that shouldn' be a problem. Maybe I should add this behavior to the inputmask.dependencyLib.jquery.js

nicholasrq commented 8 years ago

@RobinHerbots

Hmm.. still not working with React onChange, but works with native events as expected.

I've tried to attach onChange after the mask has been applied, but no luck.

RobinHerbots commented 8 years ago

@nicholasrq ,

Does react use his own eventing system?

nicholasrq commented 8 years ago

@RobinHerbots

Yep, it invokes it's own SynteticEvent's. In case of onChange react will handle native input event to correctly sync it's own state with input value.

You still can use my Pen as example if you're going to debug this particular case http://codepen.io/nicholasrq/pen/kkaEoL?editors=0010

I believe that with growing popularity of React there is a reason to support it out of the box :)

RobinHerbots commented 8 years ago

@nicholasrq ,

Maybe react.js can be the dependencylib for inputmask? In that case the inputmask will use the events from react.

nicholasrq commented 8 years ago

@RobinHerbots

Not sure for now, i'll try to investigate it. But as i know now react doesn't expose it's event system outside of react itself.

React uses it's events only inside components, so you can't use it like jQuery to handle particular events on particular elements outside of component. Also react has it's own binding system. So i don't think that it is possible to use react as dependencyLib.

From the docs of React:

Your event handlers will be passed instances of SyntheticEvent, a cross-browser wrapper around the browser's native event. It has the same interface as the browser's native event, including stopPropagation() and preventDefault(), except the events work identically across all browsers.

RobinHerbots commented 8 years ago

@nicholasrq,

I guess just make a copy of the vanilla dependencylib and replacing the events with ReactBrowserEventEmitter.ReactEventListener.dispatchEvent will do.

I will have a try

matheusbras commented 8 years ago

@nicholasrq Did you manage to get this working somehow?

eykanal commented 7 years ago

I'm not sure if this is relevant to this issue or if it should be a separate issue, but after reading the docs I'm not sure how to use a different dependencyLib. It mentions what to do if you're using require.JS, but beyond that I'm not so sure how to make a change. Would you clarify?

mufasa71 commented 7 years ago

Also, I want to mention that autoUnmask property is not working anymore with React in IE 11. #1187

knoxcard commented 7 years ago

This native code worked for me, just posting so others can easily copy and paste, if they wish.

    var d = document.getElementById('element id of your inputmaskfield')
    d.onkeyup = function() {
        window.alert(this.value)
    }
RobinHerbots commented 7 years ago

@eykanal ,

I updated the readme. I hope this makes it clearer

RobinHerbots commented 7 years ago

@nicholasrq ,

Do you have any update on this issue?

eykanal commented 7 years ago

That's much clearer, thank you!

an-kh commented 7 years ago

Found something interesting https://medium.com/@ericclemmons/react-event-preventdefault-78c28c950e46 https://github.com/erikras/react-native-listener Haven't tried it out, but may be useful.

RobinHerbots commented 7 years ago

@nicholasrq , @an-kh ,

I made some modification in the vanilla dependencylib which could fix the problem in react. Can you have a try.

an-kh commented 7 years ago

@RobinHerbots Thanks you! Seems to be working now with native dependancy library: https://jsfiddle.net/5pkeehdk/

pravdinalex commented 5 years ago

If min/max is set, we got no input event in a situation when we entered incorrect number. For example, type=integer, max=24, we entered 25 in the field, leave the field, got 24 displayed in it, but no input event fired.

Workaround about this issue topic: we can catch input event in the jQuery version of the library with it "on" binding. (I use Vue.js): mounted() { ... $(this.$el).on('input', () => { this.$emit( 'input', $(this.$el).val() ) }) } @input dont works, but $.on does