I have problem initializing vue quill to apply in a Vue3 project about a note taking function, i can make note easily but when modifying it, it return offset error everytime i click or type on the quill editor. Here is my error
quill.js?v=870ff25b:12570 Uncaught TypeError: Cannot read properties of null (reading 'offset')
at quill.js?v=870ff25b:12570:26
at Array.map (<anonymous>)
at Selection.normalizedToRange (quill.js?v=870ff25b:12567:31)
at Selection.getRange (quill.js?v=870ff25b:12556:25)
at Selection.update (quill.js?v=870ff25b:12691:43)
at quill.js?v=870ff25b:12452:12
at quill.js?v=870ff25b:12338:9
at Array.forEach (<anonymous>)
at Emitter.handleDOM (quill.js?v=870ff25b:12332:43)
at quill.js?v=870ff25b:12310:23
And here is my code:
<template>
<section id="view-note-page" class="container mt-4">
<div class="note-header-container mb-3 d-flex justify-content-between align-items-center">
<div class="note-title-container">
<label for="note-title" class="note-title-label">Title:</label>
<input
id="note-title"
type="text"
v-model="noteData.title"
class="note-title-input"
placeholder="Enter note title"
/>
</div>
<button class="btn btn-primary btn-save-changes" @click="saveNote">Save Changes</button>
</div>
<div id="post-editor" class="mb-3 flex-grow-1">
<div id="quill-editor"></div>
</div>
</section>
</template>
<script>
import { nextTick } from "vue";
import Quill from "quill";
import "quill/dist/quill.snow.css";
import { toast } from "vue3-toastify";
import "vue3-toastify/dist/index.css";
import { noteService } from "@/services/note.service";
export default {
name: "ViewNotePage",
props: {
noteId: {
type: [String, Number],
required: true,
},
},
data() {
return {
noteData: {
title: "",
content: "",
},
quillEditor: null,
};
},
methods: {
async fetchNote() {
try {
const note = await noteService.fetchNoteFromId(this.noteId);
this.noteData = note;
await this.updateQuillContent(note.content);
} catch (error) {
console.error("Failed to fetch the note:", error);
toast.error("Failed to fetch the note.", { autoClose: 2000 });
}
},
async initializeQuill() {
try {
await nextTick();
const editorElement = document.getElementById("quill-editor");
if (editorElement) {
this.quillEditor = new Quill(editorElement, {
theme: "snow",
modules: {
toolbar: [
["bold", "italic", "underline"],
[{list: "ordered"}, {list: "bullet"}],
[{header: [1, 2, 3, false]}],
["link"],
["clean"],
],
},
});
this.quillEditor.on("text-change", () => {
this.noteData.content = JSON.stringify(this.quillEditor.getContents());
});
}
} catch (error) {
console.error("Failed to initialize Quill editor:", error);
}
},
async updateQuillContent(content) {
try {
if (this.quillEditor) {
const delta = content ? JSON.parse(content) : {ops: []};
this.quillEditor.setContents(delta);
}
} catch (error) {
console.error("Failed to update Quill content:", error);
}
},
async saveNote() {
try {
if (!this.noteData.title || !this.noteData.content) {
toast.error("Please provide a title and content for the note.", {autoClose: 2000});
return;
}
await noteService.updateNote(this.noteId, this.noteData);
toast.success("Note updated successfully!", {autoClose: 2000});
this.$emit("update", this.noteData);
} catch (error) {
console.error("Failed to save the note:", error);
toast.error("Failed to update the note.", {autoClose: 2000});
}
},
},
async mounted() {
try {
await this.initializeQuill();
await this.fetchNote();
} catch (error) {
console.error("Error during component setup:", error);
}
},
watch: {
noteId: {
immediate: true,
handler(newNoteId) {
this.fetchNote();
},
},
},
};
</script>
I tried to use something similar to this I found on github but it doesnot work
// ✅ works with quill2
let quill: Quill | null = null
onMounted(() => {
quill = new Quill(...)
})
As explained in this issue, the problem is that Quill object is incompatible with Vue reactive proxy.
This can be avoided by marking it as non-reactive:
this.quillEditor = markRaw(new Quill(...));
The solution that is specific to options API is to not make quillEditor
reactive data and remove it from data
.