Quill: Extending default Quill handler for image to upload base64 data.

Created on 11 Apr 2017  路  22Comments  路  Source: quilljs/quill

I am using the lib for a mobile app and I will love to be able to extend the current functionality of the image handler to grab the image data and post it before embedding it to the editor and I was wondering if this was possible and if I could get some help in implementing this.

  1. hit the image icon
  2. quill handler runs file dialogue
  3. user clicks on file
  4. file datauri is returned by quill but the I convert that to a file and upload and use the returned link instead of base64 obj.

Thanks.

Most helpful comment

I solved the problem that upload image with url.
This is my code, hope help you:

   const editor = new Quill('#quill-editor', {
      bounds: '#quill-editor',
      modules: {
        toolbar: this.toolbarOptions
      },
      placeholder: 'Free Write...',
      theme: 'snow'
    });

      /**
       * Step1. select local image
       *
       */
    function selectLocalImage() {
      const input = document.createElement('input');
      input.setAttribute('type', 'file');
      input.click();

      // Listen upload local image and save to server
      input.onchange = () => {
        const file = input.files[0];

        // file type is only image.
        if (/^image\//.test(file.type)) {
          saveToServer(file);
        } else {
          console.warn('You could only upload images.');
        }
      };
    }

    /**
     * Step2. save to server
     *
     * @param {File} file
     */
    function saveToServer(file: File) {
      const fd = new FormData();
      fd.append('image', file);

      const xhr = new XMLHttpRequest();
      xhr.open('POST', 'http://localhost:3000/upload/image', true);
      xhr.onload = () => {
        if (xhr.status === 200) {
          // this is callback data: url
          const url = JSON.parse(xhr.responseText).data;
          insertToEditor(url);
        }
      };
      xhr.send(fd);
    }

    /**
     * Step3. insert image url to rich editor.
     *
     * @param {string} url
     */
    function insertToEditor(url: string) {
      // push image url to rich editor.
      const range = editor.getSelection();
      editor.insertEmbed(range.index, 'image', `http://localhost:9000${url}`);
    }

    // quill editor add image handler
    editor.getModule('toolbar').addHandler('image', () => {
      selectLocalImage();
    });

Quill is awesome and easy to extensible.

All 22 comments

Yes! I am also trying to do this exact same thing. We are storing the contents in a SQL database and do not want to store the base64 data of any images.

You can try something like this to overwrite the default image insert functionality and insert your own instead. @jwstevensii

this.editor = new Quill('#editor', {
      modules: { toolbar: "#toolbar"},
      placeholder: 'you can start here and make it a blast...',
      theme: 'snow'
});
this.editor.getModule("toolbar").addHandler("image", imgHandler);

So how does this image uploading works? I just cannot find good example here. Is it possible to add button to toolbar which will open my custom gallery modal where I can select one of my uploaded images or upload new and it will return image url back to editor?

I met exactly same problem, don't know how to solve it.

The imgHandler in the example is a function that gets passed a parameter, you could literally rewrite it as

function(a){
 console.log(a);
 // code that uploads your image and slots the resulting url into the editor goes here...
}

Try running tests to see what gets returned by the quill editor.

https://github.com/quilljs/quill/issues/863#issuecomment-240579430 This is very nice example, which helped me solved this problem. It is very easy to implement.

I finally solved the problem by using Ajax to upload image to server.
Here are some links that I find useful (if you want to using ajax to implement this upload function, too).
How can I upload files asynchronously?
Ajax POST request via jQuery and FormData - $_POST empty on PHP
Suggestions above are useful when you embed the upload function in your quill editor.

I solved the problem that upload image with url.
This is my code, hope help you:

   const editor = new Quill('#quill-editor', {
      bounds: '#quill-editor',
      modules: {
        toolbar: this.toolbarOptions
      },
      placeholder: 'Free Write...',
      theme: 'snow'
    });

      /**
       * Step1. select local image
       *
       */
    function selectLocalImage() {
      const input = document.createElement('input');
      input.setAttribute('type', 'file');
      input.click();

      // Listen upload local image and save to server
      input.onchange = () => {
        const file = input.files[0];

        // file type is only image.
        if (/^image\//.test(file.type)) {
          saveToServer(file);
        } else {
          console.warn('You could only upload images.');
        }
      };
    }

    /**
     * Step2. save to server
     *
     * @param {File} file
     */
    function saveToServer(file: File) {
      const fd = new FormData();
      fd.append('image', file);

      const xhr = new XMLHttpRequest();
      xhr.open('POST', 'http://localhost:3000/upload/image', true);
      xhr.onload = () => {
        if (xhr.status === 200) {
          // this is callback data: url
          const url = JSON.parse(xhr.responseText).data;
          insertToEditor(url);
        }
      };
      xhr.send(fd);
    }

    /**
     * Step3. insert image url to rich editor.
     *
     * @param {string} url
     */
    function insertToEditor(url: string) {
      // push image url to rich editor.
      const range = editor.getSelection();
      editor.insertEmbed(range.index, 'image', `http://localhost:9000${url}`);
    }

    // quill editor add image handler
    editor.getModule('toolbar').addHandler('image', () => {
      selectLocalImage();
    });

Quill is awesome and easy to extensible.

@TaylorPzreal - I get the missing ) after formal parameters error on the saveToServer function, which prevent the editor from loading altogether. Any ideas?

@TaylorPzreal thank you.

@TaylorPzreal Don't forget to implement by ourselves the ways to manage the images uploaded.

@TaylorPzreal I would add one line:

input.setAttribute('accept', 'image/*')

are u guys talking about angular 6, iam using it in angular 6, cannot figure it out

I solved the problem that upload image with url.
This is my code, hope help you:

   const editor = new Quill('#quill-editor', {
      bounds: '#quill-editor',
      modules: {
        toolbar: this.toolbarOptions
      },
      placeholder: 'Free Write...',
      theme: 'snow'
    });

      /**
       * Step1. select local image
       *
       */
    function selectLocalImage() {
      const input = document.createElement('input');
      input.setAttribute('type', 'file');
      input.click();

      // Listen upload local image and save to server
      input.onchange = () => {
        const file = input.files[0];

        // file type is only image.
        if (/^image\//.test(file.type)) {
          saveToServer(file);
        } else {
          console.warn('You could only upload images.');
        }
      };
    }

    /**
     * Step2. save to server
     *
     * @param {File} file
     */
    function saveToServer(file: File) {
      const fd = new FormData();
      fd.append('image', file);

      const xhr = new XMLHttpRequest();
      xhr.open('POST', 'http://localhost:3000/upload/image', true);
      xhr.onload = () => {
        if (xhr.status === 200) {
          // this is callback data: url
          const url = JSON.parse(xhr.responseText).data;
          insertToEditor(url);
        }
      };
      xhr.send(fd);
    }

    /**
     * Step3. insert image url to rich editor.
     *
     * @param {string} url
     */
    function insertToEditor(url: string) {
      // push image url to rich editor.
      const range = editor.getSelection();
      editor.insertEmbed(range.index, 'image', `http://localhost:9000${url}`);
    }

    // quill editor add image handler
    editor.getModule('toolbar').addHandler('image', () => {
      selectLocalImage();
    });

Quill is awesome and easy to extensible.

Your answer is very helpful, but how can I detect which image is being deleted by the user in the editor, As I want to delete the image from my server when the user deletes it

const editor = new Quill('#quill-editor', {
bounds: '#quill-editor',
modules: {
toolbar: this.toolbarOptions
},
placeholder: 'Free Write...',
theme: 'snow'
});

  /**
   * Step1. select local image
   *
   */
function selectLocalImage() {
  const input = document.createElement('input');
  input.setAttribute('type', 'file');
  input.click();

  // Listen upload local image and save to server
  input.onchange = () => {
    const file = input.files[0];

    // file type is only image.
    if (/^image\//.test(file.type)) {
      saveToServer(file);
    } else {
      console.warn('You could only upload images.');
    }
  };
}

/**
 * Step2. save to server
 *
 * @param {File} file
 */
function saveToServer(file: File) {
  const fd = new FormData();
  fd.append('image', file);

  const xhr = new XMLHttpRequest();
  xhr.open('POST', 'http://localhost:3000/upload/image', true);
  xhr.onload = () => {
    if (xhr.status === 200) {
      // this is callback data: url
      const url = JSON.parse(xhr.responseText).data;
      insertToEditor(url);
    }
  };
  xhr.send(fd);
}

/**
 * Step3. insert image url to rich editor.
 *
 * @param {string} url
 */
function insertToEditor(url: string) {
  // push image url to rich editor.
  const range = editor.getSelection();
  editor.insertEmbed(range.index, 'image', `http://localhost:9000${url}`);
}

// quill editor add image handler
editor.getModule('toolbar').addHandler('image', () => {
  selectLocalImage();
});

Your answer is very helpful, but how can I detect which image is being deleted by the user in the editor, As I want to delete the image from my server when the user deletes it

I am not sure why anyone haven't talked about it? If we are working on uploading images to server, we need to know how we can reverse it, I mean delete it just by backspacing the image in the editor.
I have tried to read through onContentChange/text-change etc. But can't find a proper way to do it.
Have anyone done it, please share your here.

So, I have done so far is this to delete the uploaded image >

this.editorInstance.on('text-change', function(delta, oldDelta, source) {
      if (source == 'api') {
        console.log("An API call triggered this change.");
        console.log(delta);
        console.log(oldDelta);
      } else if (source == 'user') {
        console.log("A user action triggered this change."); // when a user is deleting the image from editor
        console.log(delta);
        console.log(oldDelta.ops[0].insert.image); // So you will get the link of the image
      }
});

I solved the problem that upload image with url.
This is my code, hope help you:

   const editor = new Quill('#quill-editor', {
      bounds: '#quill-editor',
      modules: {
        toolbar: this.toolbarOptions
      },
      placeholder: 'Free Write...',
      theme: 'snow'
    });

      /**
       * Step1. select local image
       *
       */
    function selectLocalImage() {
      const input = document.createElement('input');
      input.setAttribute('type', 'file');
      input.click();

      // Listen upload local image and save to server
      input.onchange = () => {
        const file = input.files[0];

        // file type is only image.
        if (/^image\//.test(file.type)) {
          saveToServer(file);
        } else {
          console.warn('You could only upload images.');
        }
      };
    }

    /**
     * Step2. save to server
     *
     * @param {File} file
     */
    function saveToServer(file: File) {
      const fd = new FormData();
      fd.append('image', file);

      const xhr = new XMLHttpRequest();
      xhr.open('POST', 'http://localhost:3000/upload/image', true);
      xhr.onload = () => {
        if (xhr.status === 200) {
          // this is callback data: url
          const url = JSON.parse(xhr.responseText).data;
          insertToEditor(url);
        }
      };
      xhr.send(fd);
    }

    /**
     * Step3. insert image url to rich editor.
     *
     * @param {string} url
     */
    function insertToEditor(url: string) {
      // push image url to rich editor.
      const range = editor.getSelection();
      editor.insertEmbed(range.index, 'image', `http://localhost:9000${url}`);
    }

    // quill editor add image handler
    editor.getModule('toolbar').addHandler('image', () => {
      selectLocalImage();
    });

Quill is awesome and easy to extensible.

I am getting a missing ) error at saveToServer function, Kindly help I am in trouble figuring out, I am using javascript

@TaylorPzreal - I get the missing ) after formal parameters error on the saveToServer function, which prevent the editor from loading altogether. Any ideas?

Same here, do you get the solution if so then please share it with me..

Hi, I took the help from this discussion but I am facing an issue after uploading the image, I need to press enter event. Then only, image Url is being inserted into the editor content. Is there a way to do it while uploading the image?

@Utkarsh3587 Yes, I am having this same issue, it's a really annoying issue for content creators, is there any solution to that ? Please help needed from devs.

After inserting embed, somehow the selection should be at the end of the inserted thumbnail image to insert the url link in behind.

@TaylorPzreal - I get the missing ) after formal parameters error on the saveToServer function, which prevent the editor from loading altogether. Any ideas?

Same here, do you get the solution if so then please share it with me..

I tried this code on the quill Interactive Playground just to check for invalid syntax, and I found that some function arguments have an invalid type specification. On the definition of the function "saveToServer" and "insertToEditor" try removing the argument type (": string", ": File"). After doing this I had no errors showing up on console and the editor showed up.
Actually, it gave me a different error, but this is still invalid js syntax

Was this page helpful?
0 / 5 - 0 ratings