search

Home  >  Q&A  >  body text

Methods for passing data to custom Vue extensions in TipTap

I'm trying to pass data to a custom vue component rendered inside the tiptap editor. I can pass the default attribute, but assigning it a reactive value doesn't seem to work.

This is tiptap-node-extension.js File:

import {Node, mergeAttributes} from '@tiptap/core'
import {VueNodeViewRenderer} from '@tiptap/vue-3'
import Component from '@/views/components/vue-component.vue'

export default Node.create({
    parseHTML() {
        return [{ tag: 'vue-component' }]
    },
    renderHTML({ HTMLAttributes }) {
        return ['vue-component', mergeAttributes(HTMLAttributes)]
    },
    addNodeView() {
        return VueNodeViewRenderer(Component)
    },
})

editor The script setup part of the component:

<script setup>
import {useEditor, EditorContent, BubbleMenu} from '@tiptap/vue-3'
import StarterKit from '@tiptap/starter-kit'
import {Underline} from "@tiptap/extension-underline";
import {TextAlign} from "@tiptap/extension-text-align";
import {Link} from "@tiptap/extension-link";
import VueComponent from '@/js/tiptap-node-extension.js'


const editor = useEditor({
    extensions: [
        StarterKit,
        TextAlign.configure({ types: ['heading', 'paragraph'] }),
        Underline,
        Link,
        VueComponent.extend({
                name: 'vueComponent',
                group: 'block',
                draggable: true,
                addAttributes() {
                    return {
                        src: {
                            default: '123',
                        }
                    }
                },
            }
        ),
    ],
    content: props.modelValue,
    onUpdate: ({ editor }) => {
        emit('update:modelValue', editor.getHTML())
    },
    editable: props.locked ? false : store.admin
})

const sendDataToExtension = async (editor, event) => {
    // Triggered upon event

    ...

    state.src = '123'
    editor.chain().focus().insertContent('<vue-component/>').run()
}
</script>

and vue components :

<script setup>
import {NodeViewWrapper} from '@tiptap/vue-3'

const props = defineProps({
    node: {
        type: Object,
        required: true
    },
    updateAttributes: {
        type: Function,
        required: true,
    }
})

</script>


<template>
  <node-view-wrapper class="vue-component" data-drag-handle="">
    <p>{{ node.attrs.src }}</p>
  </node-view-wrapper>
</template>
The

default for src passes, but when I try to allocate a response object (created after installing the editor component) it ends up becoming Become undefined.

This works:

src: {
    default: '123'
}

But this is not:

...

src: {
    default: state.src
}

...

const sendDataToExtension = async (editor, event) => {
    // triggered upon event

    ...

    state.src = '123'
    editor.chain().focus().insertContent('<vue-component/>').run()

}

How to send data to the vue component created after mounting editor?

try:

editor.chain().focus().insertContent('<vue-component/>', {src: state.src}).run()

P粉957723124P粉957723124376 days ago750

reply all(1)I'll reply

  • P粉334721359

    P粉3347213592023-12-27 00:43:54

    First of all, I would recommend creating a purpose-built extension instead of using the generic VueComponent as you do now. If you build more extensions based on that extension, you will have multiple extensions competing for that tag. Move all the code you set in the extension into the actual extension and you can set any tag name you want.

    Now I think the problem is here: insertContent It looks like this:

    insertContent: (value: Content, options?: {
        parseOptions?: ParseOptions;
        updateSelection?: boolean;
    })
    

    Content declared as

    export declare type Content = HTMLContent | JSONContent | JSONContent[] | null;
    export declare type HTMLContent = string;
    export declare type JSONContent = {
        type?: string;
        attrs?: Record<string, any>;
        content?: JSONContent[];
        marks?: {
            type: string;
            attrs?: Record<string, any>;
            [key: string]: any;
        }[];
        text?: string;
        [key: string]: any;
    };
    

    In your case you have to add the src attribute to your html string, but I recommend you to use JSONContent Type in your case:

    editor.chain().focus().insertContent({type: "vueComponent", attrs:{src: state.src}}).run()
    

    The type here is the component name you set.

    Hope this makes sense and the documentation on tiptap is goodhttps:// /tiptap.dev/guide/custom-extensions/#attributes If you have any further questions please let me know.

    reply
    0
  • Cancelreply