Search code examples
javascriptreactjsdraftjs

How to limit Max Length of Draft js


How to limit max characters in draft js?

I can get length of the state like that, but how to stop updating component?

var length = editorState.getCurrentContent().getPlainText('').length;

Solution

  • You should define handleBeforeInput and handlePastedText props. In handler-functions, you check the length of current content + length of pasted text and if it reaches the maximum you should return 'handled' string.

    UPD 21.03.2018: Upgraded to the last versions of react/react-dom (16.2.0) and Draft.js (0.10.5).

    Working example - https://jsfiddle.net/Ln1hads9/11/

    const {Editor, EditorState} = Draft;
    
    const MAX_LENGTH = 10;
    
    class Container extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          editorState: EditorState.createEmpty()
        };
      }
      render() {
        return (
          <div className="container-root">
            <Editor
              placeholder="Type away :)"
              editorState={this.state.editorState}
              handleBeforeInput={this._handleBeforeInput}
              handlePastedText={this._handlePastedText}
              onChange={this._handleChange}
            />
          </div>
        );
      }
    
      _getLengthOfSelectedText = () => {
        const currentSelection = this.state.editorState.getSelection();
        const isCollapsed = currentSelection.isCollapsed();
    
        let length = 0;
    
        if (!isCollapsed) {
          const currentContent = this.state.editorState.getCurrentContent();
          const startKey = currentSelection.getStartKey();
          const endKey = currentSelection.getEndKey();
          const startBlock = currentContent.getBlockForKey(startKey);
          const isStartAndEndBlockAreTheSame = startKey === endKey;
          const startBlockTextLength = startBlock.getLength();
          const startSelectedTextLength = startBlockTextLength - currentSelection.getStartOffset();
          const endSelectedTextLength = currentSelection.getEndOffset();
          const keyAfterEnd = currentContent.getKeyAfter(endKey);
          console.log(currentSelection)
          if (isStartAndEndBlockAreTheSame) {
            length += currentSelection.getEndOffset() - currentSelection.getStartOffset();
          } else {
            let currentKey = startKey;
    
            while (currentKey && currentKey !== keyAfterEnd) {
              if (currentKey === startKey) {
                length += startSelectedTextLength + 1;
              } else if (currentKey === endKey) {
                length += endSelectedTextLength;
              } else {
                length += currentContent.getBlockForKey(currentKey).getLength() + 1;
              }
    
              currentKey = currentContent.getKeyAfter(currentKey);
            };
          }
        }
    
        return length;
      }
    
      _handleBeforeInput = () => {
        const currentContent = this.state.editorState.getCurrentContent();
        const currentContentLength = currentContent.getPlainText('').length;
        const selectedTextLength = this._getLengthOfSelectedText();
    
        if (currentContentLength - selectedTextLength > MAX_LENGTH - 1) {
          console.log('you can type max ten characters');
    
          return 'handled';
        }
      }
    
      _handlePastedText = (pastedText) => {
        const currentContent = this.state.editorState.getCurrentContent();
        const currentContentLength = currentContent.getPlainText('').length;
        const selectedTextLength = this._getLengthOfSelectedText();
    
        if (currentContentLength + pastedText.length - selectedTextLength > MAX_LENGTH) {
          console.log('you can type max ten characters');
    
          return 'handled';
        }
      }
    
      _handleChange = (editorState) => {
        this.setState({ editorState });
      }
    }
    
    ReactDOM.render(<Container />, document.getElementById('react-root'))