atom / etch

Builds components using a simple and explicit API around virtual-dom
MIT License
555 stars 57 forks source link

Add support for reverting the value of a controlled input or select #68

Open zaygraveyard opened 6 years ago

zaygraveyard commented 6 years ago

Imagine you want a "controlled" color picker, so write the following:

class ColorPicker {
  constructor(props) {
    this.props = props;
    etch.initialize(this);
  }
  handleChange(event) {
    const value = event.target.value;

    if (value !== this.props.value) {
      // revert the value so that it stays consistent with the `props`
      // this is the part that doesn't currently work <------------------------------
      etch.update(this);

      // notify the parent of the change
      this.props.onChange(value);
    }
  }
  render() {
    return <input {...this.props} type="color" onChange={this.handleChange} />;
  }
  update(nextProps) {
    if (shallowDiffers(this.props, nextProps)) {
      this.props = nextProps;
      etch.update(this);
    }
  }
}

And imagine you want to have an instance that refuses some colors:

const picker = new ColorPicker({value: '#fff', onChange: handleChange});
document.body.appendChild(picker.element)

function handleChange(color) {
  if (color.endsWith('ff')) {
    // color must have the blue at max
    picker.update({value: color, onChange: handleChange});
  }
}

This is not currently possible because when the etch.update(this) in the handleChange is called, it calls updateProps which updates the input.value only if the new value is !== than the old one. But in this case the new value is always === the old one. Ref. lib/update-props.js:59

This PR solves this case for input and select type elements.