tiptap: Problem with Multiple Editors and v-for when deleting/splice an element in the array
What’s the bug you are facing?
We know its always hard to understand others projects setup as maintainer, so i try to explain this quickly:
We use tiptap as a very versatile place to map data and mixed content, like a very smart input text field 😃

Now we have a very strange behavior of that “multiple tiptap editor” setup (they do not sharing anything to each other), when we remove an element in that array (this is what the iteration looks like and integration-map-field holds the tiptap editor instance):
<template v-for="(field,index) in item.config_json.fields">
<integration-map-field
:key="index"
v-model="item.config_json.fieldMap[field.identifier]"
:editable="true"
:label="field.label"
:type="field.type"
:required="field.required"
:fields-collection="item.pool.typeEntity.fieldsCollection"
@remove="removeField(item, index, field.identifier)"
/>
</template>
then it removes the element, but at the absolute wrong position, its no matter what, always removes the latest tiptap editor. For example we remove this one (array.splice(…)):

It removes the wrong editor, it always removes the last tiptap editor, but as you can see the array iteration has been correctly adjusted, the field title has been removed from the array:

This is so strange, i could not find anything regarding this. So i was looking for “uniqueids” or whatever. Maybe there is global instanced variable i need to consider?
- i played around with
this.editor.destroy()without any luck - i tested with vue’s $forceUpdate()
- i tested without tiptap (just added a textarea) and everything works expected.
- my environment is nuxt 2 with vuetify
Which browser was this experienced in? Are any special extensions installed?
Chrome, Firefox. It happens on all browsers
How can we reproduce the bug on our side?
Take a look here: https://codesandbox.io/s/tiptap-vue-multiple-editor-issue-oxr1lo?file=/src/App.vue
Can you provide a CodeSandbox?
Update: Yes, its easy to reproduce, just add 3 or more items and remove an item in the middle: https://codesandbox.io/s/tiptap-vue-multiple-editor-issue-oxr1lo?file=/src/App.vue
What did you expect to happen?
It should removed the editor in the row, not the last one. it always removes the last one no matter what we do 😃
Anything to add? (optional)
This is what the component looks like … i have removed unnecessary logic and markup for better readability:
The Component
<template>
<div>
<editor-content
:editor="editor"
/>
<v-btn
icon
@click="removeItem"
>
<v-icon small>icon icon-remove</v-icon>
</v-btn>
</div>
</template>
<script>
// https://stackoverflow.com/questions/48145727/insert-character-at-cursor-position-in-vue-js
import IntegrationMapFieldMapperInputSpan from './IntegrationMapFieldMapperInputSpan.vue'
import { Editor, EditorContent, Node, VueNodeViewRenderer, mergeAttributes} from '@tiptap/vue-2'
import Document from '@tiptap/extension-document'
import Text from '@tiptap/extension-text'
const Div = Node.create({
name: 'div',
group: 'block',
content: 'inline*',
parseHTML() {
return [
{ tag: 'div'},
]
},
renderHTML({ HTMLAttributes }) {
return ['div', mergeAttributes(HTMLAttributes, {style:"vertical-align: text-top; line-height:30px"}), 0]
},
})
const Variable = Node.create({
name: 'variable',
group: 'inline',
inline: true,
atom: true,
selectable: false,
addAttributes() {
// removed the attributes
},
parseHTML() {
return [
{ tag: 'span' },
]
},
renderText({ node }) {
return `${node.attrs.label}`
},
renderHTML({ node, HTMLAttributes }) {
return ['span', mergeAttributes(HTMLAttributes), node.attrs.label]
},
addNodeView() {
return VueNodeViewRenderer(IntegrationMapFieldMapperInputSpan)
}
})
export default {
components: { EditorContent },
props: {
// removed the props
},
data:() => ({
editor: null
}),
computed: {
parsedValue: function() {
// we do more things here, fulfill the array
return {
"type": "doc",
"content": contentArrays
}
}
},
mounted() {
this.editor = new Editor({
extensions: [
Document,
Div,
Text,
Variable
],
autofocus: 'end',
content: this.parsedValue,
onUpdate: () => {
const values = []
const content = this.editor.getJSON().content
// we do more things here
this.$emit('input', values)
},
})
},
beforeDestroy() {
this.editor.destroy()
},
methods: {
removeItem() {
this.$emit('removeItem')
}
}
}
</script>
Did you update your dependencies?
- Yes, I’ve updated my dependencies to use the latest version of all packages.
Are you sponsoring us?
- Yes, I’m a sponsor. 💖
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 17 (6 by maintainers)
Hey @nadar.
I’m going to take a look into this issue to find out what exactly is happening here. Thanks for reporting!