Search code examples
javascriptreactjsquill

can't call ref(also others like state, props, function, etc) on react quill custom handler


I got a problem with quill editor on react.

imageHandler() works well.
But In imageHandler(), It can't call others like state, props, function, etc as well.
I wanna call quillRef in imageHandler() that is called by module.toolbar.handlers

Below is my simple code.

import React, { Component } from 'react';
import ReactQuill from 'react-quill'; // ES6

const formats = [
  'header', 'font', 'size',
  'bold', 'italic', 'underline', 'strike', 'blockquote',
  'list', 'bullet', 'indent',
  'link', 'image', 'video'
]

class App extends Component {
  
  constructor(props) {
    super(props)
    this.state = { text: ''}
    this.handleChange = this.handleChange.bind(this)

    this.reactQuillRef = null; // ReactQuill component
    this.quillRef = null;      // Quill instance
  }
  
  modules = {
    toolbar: {
      container:  [['bold', 'italic', 'underline', 'blockquote'],
            [{'list': 'ordered'}, {'list': 'bullet'}],
            ['image'],
      ],
      handlers: {
         'image': this.imageHandler
      }
    }
  }

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

  imageHandler() {
    const input = document.createElement('input');
    input.setAttribute('type', 'file');
    input.setAttribute('accept', 'image/*');
    input.click();
    
    input.onchange = () => {
    
      const file = input.files[0];
      console.log(file); // works well
      
      // problems : can't call ref, props, function... etc
      console.log("ref : ", this.reactQuillRef, this.quillRef); // undefine
      
      // this.insertImg(); // not work (insertImg is not a function)

      console.log(this.props); // undefine
      
    };
  }

  handleChange(value) {
    this.setState({ text: value });
    this.refs.test.innerHTML = this.state.text;
  }
  
  insertImg = () => {
    console.log("insertImg",prototype);
    var range = this.quillRef.getSelection();
    let position = range ? range.index : 0;
    console.log(this.quillRef); // works well!!!!!!!!! why diffrent with imgHandler() 
    this.quillRef.insertEmbed(position, 'image','https://images.pexels.com/photos/47480/pexels-photo-47480.jpeg?auto=compress&cs=tinysrgb&h=350');
  }

  render() {
    return (
      <div className="App">
      <button onClick={this.insertImg}>Insert Img</button>
        <ReactQuill value={this.state.text}
                  onChange={this.handleChange} 
                  modules={this.modules}
                  formats={formats} 
                  ref={(el) => {this.reactQuillRef = el}}
        />

      <br/><br/>
      <div contentEditable='true' ref='test'></div>
      {this.state.text}
      </div>

    );
  }
}

export default App;

I tried many ways(all failed) and this case, not work

imageHandler() {...} to imageHandler = () => {...}




And my package.json here

{
  "name": "quill",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "fine-uploader": "^5.16.2",
    "react": "^16.3.2",
    "react-dom": "^16.3.2",
    "react-quill": "^1.2.7",
    "react-scripts": "1.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
}

Any Idea why? Does anyone give hands for me? Thank you!


Solution

  • imageHandler is not getting called becuase its not binded to App component this.

    In the object modules , this referring modules and not App component.

    save the this ref and use it inside modules object

    modules object

    constructor(){
      super();
    
    
      this.modules = {
        toolbar: {
          container: [['bold', 'italic', 'underline', 'blockquote'],
          [{ 'list': 'ordered' }, { 'list': 'bullet' }],
          ['image'],
          ],
          handlers: {
            'image': this. imageHandler
          }
        }
      }
    }
    

    Check codesandbox#working demo