sam
sam

Reputation: 1

office-ui-fabric-react / TextField input properties alternative to onChanged

I'm currently using the TextField from office UI fabric and using the onChanged property to assign my prop in react the value being entered similar to their GitHub example.

However, the event handler is called for each element being entered. How can I make a call to the event handler(this._onChange) only when the user finishes entering the entire text (eg on focus dismiss, etc)?

I'm guessing that would be more efficient than logging an event with each letter being entered.

New to react. Appreciate your help!

Upvotes: 0

Views: 5145

Answers (3)

krolson
krolson

Reputation: 186

You can keep your state and UI in sync but use things like your own deferred validation error-check functions to check if the value is good/bad AND/or if you want to do something like logging based on the value only after a certain amount of time passes. Some examples from this page copied below for quick reference - you can do whatever you want in your "_getErrorMessage" function (https://github.com/OfficeDev/office-ui-fabric-react/blob/master/packages/office-ui-fabric-react/src/components/TextField/examples/TextField.ErrorMessage.Example.tsx):

            <TextField
              label="Deferred string-based validation"
              placeholder="Validates after user stops typing for 2 seconds"
              onGetErrorMessage={this._getErrorMessage}
              deferredValidationTime={2000}
            />
            <TextField
              label="Validates only on focus and blur"
              placeholder="Validates only on input focus and blur"
              onGetErrorMessage={this._getErrorMessage}
              validateOnFocusIn
              validateOnFocusOut
            />

Upvotes: 0

kevintcoughlin
kevintcoughlin

Reputation: 482

You may consider using React's onBlur prop which will be invoked when the input loses focus. Here is an example Codepen which window.alert's the <TextField> component's current value when it loses focus: https://codepen.io/kevintcoughlin/pen/zmdaJa?editors=1010.

Here is the code:

const { 
  Fabric,
  TextField
} = window.Fabric;

class Content extends React.Component {
  public render() {    
    return (
      <Fabric>
        <TextField onBlur={this.onBlur} />
      </Fabric>
    );
  }

  private onBlur(ev: React.FocusEvent<HTMLInputElement>) {
    window.alert(ev.target.value);
  }
}

ReactDOM.render( 
  <Content />,
  document.getElementById('content')
);

I hope you find that helpful.

References

Upvotes: 0

Tyler
Tyler

Reputation: 2400

This is more of an in-general way React uses the input onChange event. With React, you want to keep the value of your input in state somewhere, whether that is component state or a global store like Redux. Your state and UI should always be in sync. Because of this, the onChange event fires for every character that is entered/removed so that you can update that state to reflect the new value. Inputs written this way are called Controlled Components and you can read more about them and see some examples at https://reactjs.org/docs/forms.html.

That being said, you can detect when the user leaves the input with the onBlur event, though I would not recommend using that to update the state with the value as you'll see that a Controlled Component will act read-only when you don't update the state in the onChange event. You will have to use an Uncontrolled Component, typically setting the initial value with defaultValue instead of value and making things more difficult for yourself.

// CORRECT IMPLEMENTATION
class ControlledForm extends React.Component {
  constructor(props, context) {
    super(props, context);
    
    this.state = {
      name: 'example'
    };
    
    this.handleNameChange = this.handleNameChange.bind(this);
  }
  
  handleNameChange(e) {
    this.setState({
      name: e.target.value
    });
  }
  
  render() {
    return (
      <div>
        <h1>Controlled Form</h1>
        <input type="text" value={this.state.name} onChange={this.handleNameChange} />
        <p>{this.state.name}</p>
      </div>
    );
  }
}

// INPUT DOES NOT WORK
class BuggyUncontrolledForm extends React.Component {
  constructor(props, context) {
    super(props, context);
    
    this.state = {
      name: 'example'
    };
  }
  
  render() {
    return (
      <div>
        <h1>Buggy Uncontrolled Form</h1>
        <input type="text" value={this.state.name}  />
        <p>{this.state.name}</p>
      </div>
    );
  }
}

// NOT RECOMMENDED
class UncontrolledForm extends React.Component {
  constructor(props, context) {
    super(props, context);
    
    this.state = {
      name: 'example'
    };
    
    this.handleNameChange = this.handleNameChange.bind(this);
  }
  
  handleNameChange(e) {
    this.setState({
      name: e.target.value
    });
  }
  
  render() {
    return (
      <div>
        <h1>Uncontrolled Form</h1>
        <input type="text" defaultValue={this.state.name} onBlur={this.handleNameChange} />
        <p>{this.state.name}</p>
      </div>
    );
  }
}

ReactDOM.render(
  <div>
    <ControlledForm />
    <BuggyUncontrolledForm />
    <UncontrolledForm />
  </div>
, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions