maria
maria

Reputation: 413

How to show character counter in a React-quill

I would like to add a character counter on my React Quill. At the moment I have a character limiter of 950. The problem is that the user must be aware that the number of characters must not be more than 950, thus the character counter I've tried adding getLength() on the render but gives me an error. This is my code:

attachQuillRefs = () => {
    if (typeof this.reactQuillRef.getEditor !== "function") return;
    this.quillRef = this.reactQuillRef.getEditor();
  };

  //Handles changes to description field
  handleDetailChange(value) {
    var limit = 950;
    var quill = this.quillRef;
    quill.on("text-change", function (delta, old, source) {
      if (quill.getLength() > limit) {
        quill.deleteText(limit, quill.getLength());
      }
    });
    this.setState({
      detail: value,
    });
  }

at Render:

<ReactQuill
     ref={(el) => {
        this.reactQuillRef = el;
     }}
     onChange={this.handleDetailChange}
        value={this.state.detail || ""}
     >
     <p>{this.reactQuillRef.getLength() + "/950"}</p>
</ReactQuill>

Upvotes: 1

Views: 5560

Answers (3)

ezennnn
ezennnn

Reputation: 1427

I was able to get it to work with @Juan Lanus's advice, using UnprivilegedEditor provided by onChange in react-quill

This is implemented in NextJS 12 - (React 18)

You may refer to sample snippet below:

import { useState } from 'react'
import dynamic from 'next/dynamic'
import 'react-quill/dist/quill.snow.css'
import { ReactQuillProps, UnprivilegedEditor } from 'react-quill'
import { DeltaStatic, Sources } from 'quill'

const ReactQuill = dynamic(() => import('react-quill'), { ssr: false })

export interface ICustomRichTextEditorProps extends ReactQuillProps {
  value?: string
  maxLength?: number
  errorMessage?: string
  helperText?: string
  disabled?: boolean
}

const RichTextEditor = ({
  placeholder,
  value,
  onChange,
}: ICustomRichTextEditorProps) => {
  const [count, setCount] = useState<number>(0)
  const [shrink, setShrink] = useState(false)

  const handleOnChange = (
    value: string,
    deltaOp: DeltaStatic,
    sources: Sources,
    editor: UnprivilegedEditor,
  ) => {
    const characterCount = editor.getLength() - 1

    console.log(characterCount)
    
    // you can also choose to assign the character count with React useState like so:
    // setCount(characterCount)

    onChange && onChange(value, deltaOp, sources, editor)
  }

  return (
    <div>
      <ReactQuill
        value={value}
        placeholder={placeholder}
        onChange={handleOnChange}
        // ... other props
      />
    </div>
  )
}

export default RichTextEditor

Note that I am using react-quill beta version, which is what i found to be most compatible to Next12 per time when posting in this thread

 "react-quill": "^2.0.0-beta.4",

Upvotes: 0

Juan Lanus
Juan Lanus

Reputation: 2344

react-quill event handlers expose 4 args, like this:
onChange(content, delta, source, editor)
The 4th argument, editor, is a reference to an "unprivileged" editor that exposes a restricted subset of the Quill API.
One of the methods provided is getLength() that returns the content length in characters.
https://github.com/zenoamaro/react-quill#the-unprivileged-editor

This solves the length calculation.
As of the limit, you can display not the number of chars entered, but 950 minus said number, in an element that turns red when the limit is exceeded (less than zero characters left).

Upvotes: 2

Thrinath Reddy
Thrinath Reddy

Reputation: 320

1)create a custom module and register it with qill as below.

    class Counter {
    constructor(quill, options) {
      this.quill = quill;
      this.options = options;
      this.container = document.querySelector(options.container);
      quill.on('text-change', this.update.bind(this));
      this.update();  // Account for initial contents
    }

    calculate() {
      let text = this.quill.getText().trim();
      if (this.options.unit === 'word') {
        text = text.trim();
        // Splitting empty text returns a non-empty array
        return text.length > 0 ? text.split(/\s+/).length : 0;
      } else {
        return text.length;
      }
    }

    update() {
      var length = this.calculate();
      var label = this.options.unit;
      if (length !== 1) {
        label += 's';
      }
      this.container.innerText = length + ' ' + label;
    }
  }
 Quill.register('modules/counter', Counter);

2) then add below code to modules as shown in image.

counter: {
    container: '#counter',
    unit: 'character'
  }

enter image description here

3) now you can add a new div tag under quilleditor tag with counter id.

<ReactQuill
     ref={(el) => {
        this.reactQuillRef = el;
     }}
     onChange={this.handleDetailChange}
        value={this.state.detail || ""}
     >
     <p>{this.reactQuillRef.getLength() + "/950"}</p>
</ReactQuill>
<div id="counter">0</div>

enter image description here

Upvotes: 1

Related Questions