Search code examples
vue.jsvuejs3wysiwygquillvue-quill-editor

Quill Editor won't display v-model in input field (Vue 3)


I want to display some html, fetched from a database inside of quill editor. The html seems to be fine (displayed in <p> paragraph) and is bound to quill editor via v-model but it just does not get displayed:

<template>
  <div id="text-editor" class="text-editor">
    <quill-editor :modules="modules" :toolbar="toolbar" v-model:content="store.re.body" contentType="html"/>
    <p>{{store.re.body}}</p>
  </div>
</template>


<script setup>
import BlotFormatter from 'quill-blot-formatter'
import store from "../../../js/store";

store.re.body = ''

const modules = {
    module: BlotFormatter,
}

const toolbar = [
    [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
    [{ 'size': ['small', false, 'large', 'huge'] }],
    ['bold', 'italic', 'underline', 'strike'],
    ['blockquote', 'code-block'],
    [{ 'align': [] }],
    [{ 'list': 'ordered'}, { 'list': 'bullet' }],
    [{ 'color': [] }, { 'background': [] }],
    [{ 'font': [] }],
    ['link', 'image', 'video'],
    ['clean']
];
</script>

This is where the data gets fetched from the database (inside another vue component):

axios.get('/get-blog', {
        params: {
            id: state.id
        }
    })
    .then(res => {
        state.body = store.re.body = res.data[0].body
    })
    .catch(err => {
        state.error = true
        setTimeout(() => state.error = false, 5000)
    })

I am using store.re.body (reactive store) to transport it to quill editor.

store.js:

import {reactive} from "vue";

const re = reactive({})

export default {
    re
}

Here you can see the editor page displayed, below with working <p> paragraph but the editor input stays empty:

enter image description here


Solution

  • The quill-editor component does not watch props.content (vueup/vue-quill#35). The watch was removed in an attempt to fix another bug, where the cursor would reset to the beginning of the line.

    As a workaround, add your own watch on content, and call quill-editor's setHTML() with the new value. However, you'll need to move the cursor to the end of the line (using Quill's setSelection()) to workaround the bug mentioned above:

    <template>
      <quill-editor ref="quill" v-model:content="content" ⋯/>
    </template>
    
    <script setup>
    import store from '@/store'
    import { watch, ref, nextTick } from 'vue'
    
    const content = ref('')
    const quill = ref(null)
    let newContent = ''
    
    watch(content, newValue => {
      newContent = newValue
      store.re.body = newValue
    })
    
    watch(
      () => store.re.body,
      newValue => {
        if (newContent === newValue) return
    
        quill.value.setHTML(newValue)
    
        // Workaround https://github.com/vueup/vue-quill/issues/52
        // move cursor to end
        nextTick(() => {
          let q = quill.value.getQuill()
          q.setSelection(newValue.length, 0, 'api')
          q.focus()
        })
      }
    )
    
    ⋮
    </script>
    
    <template>
      <quill-editor ref="quill" ⋯/>
    </template>
    

    demo