Tiptap: How to set async content data?

Created on 6 Jan 2019  路  8Comments  路  Source: ueberdosis/tiptap

I have data that loaded async after Tiptap is mounted. I can't set content

For now the only way I found is to watch data loaded, but this way I have the issue that it's setting after every charachter I type

watch: {
    value () {
      if (this.value) {
        this.editor.setContent(this.value)
        // this.html = this.editor.getHTML()
      }
    }
  }

Where and how to set data?

question

Most helpful comment

I had the same problem. The only solution to this is the following:

watch: {
    value() {
        if(this.editor.getHTML() == '<p></p>' && this.value) {
            this.editor.setContent(this.value);
        }
    }
}

Its an ugly solution, but it works. Would love to see a better one.

All 8 comments

I'm not sure what you mean with I can't set content? Do you have some error? What do you expect?

Here is a sandbox with async setting content.

@philippkuehn hey, thanks for response.

My issue is little bit different - https://codesandbox.io/s/o7k25m8q7z

And if I try to fix it with watch then I have this cursor jumping

watch: {
    value () {
      if (this.value) {
        this.editor.setContent(this.value)
        // this.html = this.editor.getHTML()
      }
    }
  }

The only way I found is to use one-time watcher. Is there other way?

I had the same problem. The only solution to this is the following:

watch: {
    value() {
        if(this.editor.getHTML() == '<p></p>' && this.value) {
            this.editor.setContent(this.value);
        }
    }
}

Its an ugly solution, but it works. Would love to see a better one.

Ok, so the question is: what do you expect in the time between your editor is created and the data is asynchronously loaded. Let's say that's two seconds between these two events. How the editor should behave in these two seconds?

  • should I be able to type?
  • what happens with that content whenever the asynchronously content is loaded?

I would still recommend to mount the editor after the content is loaded.

@philippkuehn

what do you expect in the time between your editor is created and the data is asynchronously loaded

I am ok to load editor after content is loaded. But the thing is - there's NO content sometimes. What should I do if there's no preloaded content? User still needs to input. Imagine CRUD editor. I don't want to have 2 components for CreateArticle and UpdateArticle. What should I do then?

@bernhardh thank you for solution, it works like I expect. Also wonder if there's better way?

@bernhardh here's suggestion how to get rid of this watcher (it is working on every key stroke)

mounted () {
    this.unwatch = this.$watch('value', this.setInitialContent)
  },
methods: {
    setInitialContent (content) {
      if(this.editor.getHTML() == '<p></p>') {
        this.editor.setContent(content)
        this.unwatch()
      }
    }
  }

this way watcher will triggered only once!

For sync value which already initialized. Like prop.

in mounted value already setted. Watch is never called.
If you provide prop which already initialized you should use v-bind.

in props:
props['value'],
in data:
data() {
            console.log('editor created in data')
            return {
                /* html: '', */
                editor: new Editor({
                    extensions: [
                        new Blockquote(),new BulletList(),new CodeBlock(),new HardBreak(),new Heading({ levels: [1, 2, 3] }),
                        new ListItem(),new OrderedList(),new Image(),
                        new TodoItem(),new TodoList(),new Link(),
                        new Bold(),new Code(),new Italic(),new Strike(),new HorizontalRule(),
                        new Underline(),new History(),new Table({resizable: true,}),
                        new TableHeader(),new TableCell(),new TableRow(),new TrailingNode({node: 'paragraph',notAfter: ['paragraph']}),
                    ],
                    onUpdate: /* debounce( */({ getHTML }) => {//maybe we should make it debounce?
                        /* this.html=getHTML(); */
                        /* if (this.html === '<p></p>')this.html = ''; */
                        this.$emit('input', getHTML());
                    }/* , 500) */
                }),
            }
        },

in mounted:
mounted () {
            this.editor.setContent(this.value)
        }

So, there 2 way's to initialize data:
Second way more better, just use contsructor, option content provide initialize content:

export default {
        props:['value'],
        data() {
                 console.log('editor created in data'); //value already initialized there
                 return {
                /* html: '', */
                editor: new Editor({
                                 content:this.value,

Don't forget get content, with vue ref's or with emit's, like in first example(onUpdate + input emit).

Was this page helpful?
0 / 5 - 0 ratings