Niaz Estefaie
Niaz Estefaie

Reputation: 577

How to bind content of Tiptap editor?

I'm using the Tiptap editor and I have issues accessing the content of the editor.

I need to post the content of the editor to an API so I need the content. Here is my code:

import tippy from "tippy.js";
import { Editor, EditorContent, VueRenderer } from "@tiptap/vue-2";
import Document from "@tiptap/extension-document";
import Paragraph from "@tiptap/extension-paragraph";
import Text from "@tiptap/extension-text";

export default {
    components: {
        EditorContent
    },

    props: {
        comment_type: String,
        comment_text: String,
        comment_id: Number,
        edit_mode: Boolean
    },

    data() {
        return {
            editor: null,
            limit: 280,
            users: [],
            comment_da: {},
            edit_comment_da: {}
        };
    },
    
    watch: {
        comment_text(value) {
            console.log(value);
            this.editor.setContent(value);
        }
    },

    mounted() {
        const self = this;
        const CustomParagraph = Paragraph.extend({
            addKeyboardShortcuts() {
                return {
                    // ↓ your new keyboard shortcut
                    "Shift-Enter": () => self.addComment()
                };
            }
        });
        this.editor = new Editor({
            extensions: [
                Document,
                CustomParagraph,
                Text,
            ],
            content: this.comment_text
        });
    },

    beforeDestroy() {
        this.editor.destroy();
    },
  }
<template>
  <div>
    <editor-content :editor="editor" class="form-control"/>
  </div>
</template>

In the parent component I have some properties which I need to pass to the Tiptap editor:

import editor from "./components/editor";

new Vue({
  components: {
        editor
    },
    data() {
      comment_da: {},
      comment_text: "",
    }
})
<div class="m-messenger__form-controls">
    <editor 
        v-model="comment_text"
        :comment_text="comment_text"
        :comment_type="'comment'"
        :comment_id="comment_da.id"
    />
</div>

I cannot access the editor content. I've tried this solution but I'm getting this error constantly while typing in it:

Error: "getHTML is not a function"

Upvotes: 6

Views: 12085

Answers (1)

Niaz Estefaie
Niaz Estefaie

Reputation: 577

I found the answer in the Tiptap documentation:

import editor from "./components/editor";

new Vue({
  components: {
        editor
    },
    data() {
      comment_da: {},
      comment_text: "",
    }
})
<div class="m-messenger__form-controls">
    <editor 
        v-model="comment_text"
        :comment_text="comment_text"
        :comment_type="'comment'"
        :comment_id="comment_da.id"
    />
</div>

import tippy from "tippy.js";
import { Editor, EditorContent, VueRenderer } from "@tiptap/vue-2";
import Document from "@tiptap/extension-document";
import Paragraph from "@tiptap/extension-paragraph";
import Text from "@tiptap/extension-text";

export default {
    components: {
        EditorContent
    },

    props: {
        comment_type: String,
        comment_text: String,
        comment_id: Number,
        edit_mode: Boolean
    },

    data() {
        return {
            editor: null,
            limit: 280,
            users: [],
            comment_da: {},
            edit_comment_da: {}
        };
    },
    
    watch: {
        comment_text(value) {
            console.log(value);
            this.editor.setContent(value);
        }
    },

    mounted() {
        const self = this;
        const CustomParagraph = Paragraph.extend({
            addKeyboardShortcuts() {
                return {
                    // ↓ your new keyboard shortcut
                    "Shift-Enter": () => self.addComment()
                };
            }
        });
        this.editor = new Editor({
            extensions: [
                Document,
                CustomParagraph,
                Text,
                Mention.configure({
                    HTMLAttributes: {
                        class: "mention"
                    },
                    suggestion: {
                        items: query => {
                            var self = this;
                            const search_user = new crud(
                                "/chat/mention/" + query
                            );
                            search_user.get_all_data(true, false, data => {
                                self.users = data.data;
                            });
                            return this.users.filter(item =>
                                item.name
                                    .toLowerCase()
                                    .startsWith(query.toLowerCase())
                            );
                        },
                        render: () => {
                            let component;
                            let popup;

                            return {
                                onStart: props => {
                                    component = new VueRenderer(MentionList, {
                                        parent: this,
                                        propsData: props
                                    });

                                    popup = tippy("body", {
                                        getReferenceClientRect:
                                            props.clientRect,
                                        appendTo: () => document.body,
                                        content: component.element,
                                        showOnCreate: true,
                                        interactive: true,
                                        trigger: "manual",
                                        placement: "bottom-start"
                                    });
                                },
                                onUpdate(props) {
                                    component.updateProps(props);

                                    popup[0].setProps({
                                        getReferenceClientRect: props.clientRect
                                    });
                                },
                                onKeyDown(props) {
                                    return component.ref?.onKeyDown(props);
                                },
                                onExit() {
                                    popup[0].destroy();
                                    component.destroy();
                                }
                            };
                        }
                    }
                })
            ],
            content: this.comment_text,
            onUpdate() {
                // You can access to both HTML and JSON type of your content
                const json = this.getJSON();
                const html = this.getHTML();
                // send the content to an API here
                this.comment_text = json.content[0].content[0].text
                    ? json.content[0].content[0].text
                    : "";
            }
        });
    },

    beforeDestroy() {
        this.editor.destroy();
    },
  }
<template>
  <div>
    <editor-content :editor="editor" class="form-control"/>
  </div>
</template>

If you are curious, you can take a look at onUpdate part of my code for get the changes.

Upvotes: 11

Related Questions