react-draft-wysiwyg icon indicating copy to clipboard operation
react-draft-wysiwyg copied to clipboard

how to set maxlength

Open shaomingming008 opened this issue 7 years ago • 15 comments

hello,I want to set maxlength but I can not find any apis to set

shaomingming008 avatar Oct 20 '17 08:10 shaomingming008

Hi, I was handling the same issue as you.

Here is the solution:

  • Based on this 1. demo with HTML content ( https://jpuri.github.io/react-draft-wysiwyg/#/demo) I was able to do this:
  onEditorStateChange = (editorState) => {
    this.setState({
      editorState
    });
  };

  handleBeforeInput = (input) => {
    if (this.props.maxLength) {
      if (draftToHtml(convertToRaw(this.state.editorState.getCurrentContent())).length >= this.props.maxLength) {
        return 'handled';
      }
    }
  };


<Editor
  editorState={editorState} //this is actual state of editor
  onEditorStateChange={this.onEditorStateChange}
  handleBeforeInput={this.handleBeforeInput} // THIS IS THE IMPORTANT PART
/>

Basically it's preventing any other input if maxLength props is passed to my component and then use current "html as string" length to compare with editorState.

If you want to know more about draftJS handling, read this. https://github.com/facebook/draft-js/blob/master/docs/APIReference-Editor.md#cancelable-handlers-optional

I hope this helps.

@jpuri Let me know if my approach is correct, thanks

tomffee avatar Dec 04 '17 12:12 tomffee

@tomffee this can't work. because the handleBeforeInput props is not passed to draft-js

chaosforfun avatar Jan 15 '18 08:01 chaosforfun

@tomffee : approach looks good. @chaosforfun : all additional props passed to wysiwyg are passed down to the draft editor.

jpuri avatar Jan 15 '18 14:01 jpuri

@jpuri https://github.com/jpuri/react-draft-wysiwyg/blob/84199ad37ab3f7c71e402687e3c824599091dd85/src/Editor/index.js#L316 the filterEditorProps will filter handleBeforeInput

chaosforfun avatar Jan 16 '18 08:01 chaosforfun

@chaosforfun: This filter function is not the usual js filter, it returns the filtered out props instead

Reference: https://github.com/jpuri/react-draft-wysiwyg/blob/84199ad37ab3f7c71e402687e3c824599091dd85/src/utils/common.js#L44-L55

So, all additional props passed to wysiwyg are actually indeed passed to draft-js Editor component. including handleBeforeInput

@tomffee good approach, but might need to consider handlePastedText as well.

endiliey avatar May 03 '18 15:05 endiliey

@jpuri Hello, this issue had official api now? I also want set maxLength to limit input, look forward to your reply, thanks!

wonghoman avatar Jul 04 '18 06:07 wonghoman

I'm not sure why, but that proposal is not working for me. Any news about this feature?

BrodaNoel avatar Mar 26 '19 22:03 BrodaNoel

Solved this issue. Just added handlePastedText and handleBeforeInput to Editor. Something like this:

<Editor 
  handleBeforeInput={val => {
    const textLength = editorValue.getCurrentContent().getPlainText().length;
    if (val && textLength >= maxLength) {
        return 'handled';
     }
     return 'not-handled';
   }}
  handlePastedText={val => {
     const textLength = editorValue.getCurrentContent().getPlainText().length;
     return ((val.length + textLength) >= maxLength);
    }}
...
/>

where maxLength is your number of limit and editorValue is your current state of Editor

VadSiam avatar Jan 08 '20 14:01 VadSiam

@VadSiam I am using the same approach as yours, but the issue that I am facing is by returning 'handled' instructs the editor that the command has been handled and no more work is required, but what I want to add the following to it as well.

  1. Notify the end-user with an error message that they won't be able to type or paste anything further as maxLength is exceeded.

  2. If the text length of the pasted text is more than the maxLength, then at least slice the test till max length and paste that and show the errorMsg of maxLength.

not able to find any proper method to update the editorState, with the sliced text.

Any Suggestions?

monk786 avatar Jul 15 '20 06:07 monk786

@monk786 I played around with this for a while and came up with a solution, @jpuri I guess with this we can close this issue as well -> As @VadSiam explained, handledBeforeInput would be implemented this way ->

handleBeforeInput = input => {
        const inputLength = this.state.editorState
            .getCurrentContent()
            .getPlainText().length;
        if (input && inputLength >= maxChars) {
            return "handled";
        }
    };

Now for slicing the content when copying, we would need to use the Modifier from Draft-JS, you can refer the documentation here. So the handledPastedText ->

    handlePastedText = input => {
        const inputLength = this.state.editorState
            .getCurrentContent()
            .getPlainText().length;
        let remainingLength = maxChars - inputLength;
        if (input.length + inputLength >= maxChars) {
            const newContent = Modifier.insertText(
                this.state.editorState.getCurrentContent(),
                this.state.editorState.getSelection(),
                input.slice(0,remainingLength)
            );
            this.onEditorStateChange(
                EditorState.push(
                    this.state.editorState,
                    newContent,
                    "insert-characters"
                )
            );
            return true;
        } else {
            return false;
        }
    };

Mind you here the onEditorStateChange is just the onChange method for updating the state of the editor. With this, it will be handled.

Gurubalan-GIT avatar Aug 07 '20 08:08 Gurubalan-GIT

Max-length it's kind of the default attribute for text-area. Such trivial things should be implemented by the library itself.

minbelapps avatar May 05 '22 09:05 minbelapps

@Gurubalan-GIT @VadSiam This is only working if the editor has only text inside. max-length check is not working if markup is applied to the text like bold or italics. Can anyone please help me in this case.

StarVandaliser avatar Jan 17 '23 11:01 StarVandaliser

Hi, I was handling the same issue as you.

Here is the solution:

  • Based on this 1. demo with HTML content ( https://jpuri.github.io/react-draft-wysiwyg/#/demo) I was able to do this:
  onEditorStateChange = (editorState) => {
    this.setState({
      editorState
    });
  };

  handleBeforeInput = (input) => {
    if (this.props.maxLength) {
      if (draftToHtml(convertToRaw(this.state.editorState.getCurrentContent())).length >= this.props.maxLength) {
        return 'handled';
      }
    }
  };


<Editor
  editorState={editorState} //this is actual state of editor
  onEditorStateChange={this.onEditorStateChange}
  handleBeforeInput={this.handleBeforeInput} // THIS IS THE IMPORTANT PART
/>

Basically it's preventing any other input if maxLength props is passed to my component and then use current "html as string" length to compare with editorState.

If you want to know more about draftJS handling, read this. https://github.com/facebook/draft-js/blob/master/docs/APIReference-Editor.md#cancelable-handlers-optional

I hope this helps.

@jpuri Let me know if my approach is correct, thanks

handlebeforeInput is not acceptable new version of editor

ced-shaileshverma avatar May 17 '23 16:05 ced-shaileshverma

Hello everybody,

I am having trouble setting the maxLength property on this component. Has anyone found a solution?

belkacem-oussama avatar Jun 05 '23 10:06 belkacem-oussama

Here is the version I'm using. It's handling copy - paste mechanism Not perfect, but it does the job for me

  // get selected text
  const getSelectionText = (editorState: EditorState) => {
    var selectionState = editorState.getSelection();
    var anchorKey = selectionState.getAnchorKey();
    var currentContent = editorState.getCurrentContent();
    var currentContentBlock = currentContent.getBlockForKey(anchorKey);
    var start = selectionState.getStartOffset();
    var end = selectionState.getEndOffset();
    var selectedText = currentContentBlock.getText().slice(start, end);
    return selectedText;
  };

  // handling pasting text.. damn !
  const handlePastedText = (text: string, html: string | undefined, editorState: EditorState) => {
    if (!props.maxLength) return 'not-handled';

    const getRemainingTextLength = (editorState: EditorState, maxLength: number, selectedTextLength: number) => {
      const inputLength = editorState.getCurrentContent().getPlainText().length;
      let remainingLength = Math.max(0, maxLength - (inputLength - selectedTextLength));
      return remainingLength;
    };

    let currentEditorState: EditorState = editorState;
    let selectedTextLength = getSelectionText(currentEditorState).length;
    let remainingLength = getRemainingTextLength(currentEditorState, props.maxLength, selectedTextLength);

    if (remainingLength <= 0) return 'handled';

    if (remainingLength > 0) {
      let newContent: ContentState;
      let textToPaste = text;

      // replacing selected text
      if (selectedTextLength > 0) {
        const length = Math.min(selectedTextLength, text.length);
        let replacedText = text.slice(0, length);
        newContent = Modifier.replaceText(currentEditorState.getCurrentContent(), currentEditorState.getSelection(), replacedText);
        currentEditorState = EditorState.push(currentEditorState, newContent, 'insert-characters');
        if (currentEditorState) {
          setEditorState(currentEditorState);
        }
        textToPaste = text.slice(length - 1, text.length);
      }

      if (textToPaste.length > 0) {
        let selectedTextLength = getSelectionText(currentEditorState).length;
        let remainingLength = getRemainingTextLength(currentEditorState, props.maxLength, selectedTextLength);

        if (remainingLength <= 0) return 'handled';

        if (remainingLength > 0) {
          newContent = Modifier.insertText(currentEditorState.getCurrentContent(), currentEditorState.getSelection(), textToPaste.slice(0, remainingLength));
          currentEditorState = EditorState.push(currentEditorState, newContent, 'insert-characters');
          if (currentEditorState) {
            setEditorState(currentEditorState);
          }
        }
      }

      return 'handled';
    }
    return 'not-handled';
  };

Mimetis avatar Jul 23 '23 16:07 Mimetis