question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

How to use nested nodes inside a Vue Component

See original GitHub issue

Which part of the documentation have you read? https://next.tiptap.dev/examples/interactive

Did you find the content helpful? Yes, but i think that what we are trying to develop is something that is yet to be covered, or we just didn’t have the full understanding of how things work

What was hard to understand, missing or misleading? We are trying to build a Quiz with Multiple Choices, we were able to get something out of it, but the way it works seems a bit off, we used inputs in the vue component to synchronise the attributes (eg: title, description) with the custom node, but we would like to use a heading and paragraph from the tiptap extensions, to use the getJSON() method to output our custom node with content and attrs inside of it. Is it possible to add two or more nodes of content inside a custom node within a vue component?

What else? Here is what we tried to do, hope it was in the right direction

Vue Component

<template>
  <node-view-wrapper class="block-wrapper">
    <div class="question-container" v-if="state.studentAnswer.index < 0">
      <p class="green-subtitle">Exercício</p>
      <div class="title">{{ state.title }}</div>
      <div class="description">{{ state.description }}</div>
      <div class="black-subtitle">Escolha abaixo</div>
      <div
        class="answer-wrapper"
        :class="{
          'answer-wrapper-correct':
            index === state.studentAnswer.index && state.studentAnswer.isCorrect
        }"
        v-for="(answer, index) in state.answers"
        :key="index"
        @click="() => verifyAnswer(index)"
      >
        {{ answer.text }}
      </div>
    </div>
    <div class="answer-container" v-if="state.studentAnswer.index >= 0">
      <p class="green-subtitle">Resposta</p>
      <div class="answer-title">{{ state.title }}</div>
      <div
        class="correct-answer-container"
        v-if="state.studentAnswer.isCorrect"
      >
        <div class="black-subtitle">Acertou!</div>
        <div class="correct-answer">
          {{ state.answers[state.studentAnswer.index].text }}
        </div>
      </div>
      <div class="incorrect-answer-container" v-else>
        <div class="black-subtitle">Sua Resposta:</div>
        <div class="incorrect-answer">
          {{ state.answers[state.studentAnswer.index].text }}
        </div>
        <div class="black-subtitle">Resposta Certa:</div>
        <div class="correct-answer">
          {{ state.answers[correctAnswerIndex].text }}
        </div>
      </div>
      <div class="answer-complement-text">
        <p>{{ state.answerComplementText }}</p>
      </div>
      <div class="page-break-wrapper">
        <hr />
        <button @click="() => {}">
          Avançar
        </button>
      </div>
    </div>
  </node-view-wrapper>
</template>
<script lang="ts">
import { computed, defineComponent, reactive } from 'vue'
import { NodeViewWrapper } from '@tiptap/vue-3'
export default defineComponent({
  name: 'MultipleChoice',
  components: {
    NodeViewWrapper
  },
  setup() {
    const state = reactive({
      title:
        '',
      description:
        '',
      answers: [
        {
          text:
            '',
          isCorrect: false
        },
        {
          text:
            '',
          isCorrect: true
        },
        {
          text:
            '',
          isCorrect: false
        }
      ],
      studentAnswer: {
        index: -1,
        isCorrect: false
      },
      answerComplementText:
        ''
    })
    const correctAnswerIndex = computed(() =>
      state.answers.findIndex(answer => answer.isCorrect)
    )
    const verifyAnswer = (index: number) => {
      state.studentAnswer.index = index
      state.studentAnswer.isCorrect = state.answers[index].isCorrect
    }
    return { state, verifyAnswer, correctAnswerIndex }
  }
})

Typescript Node Implementation

import { Command, mergeAttributes, Node } from '@tiptap/core'
import { VueNodeViewRenderer } from '@tiptap/vue-3'
import Component from './index.vue'
declare module '@tiptap/core' {
  interface Commands {
    multipleChoice: {
      addMultipleChoiceBlock: () => Command
    }
  }
}
export default Node.create({
  name: 'multipleChoice',
  group: 'block',
  atom: true,
  draggable: true,
  addCommands() {
    return {
      addMultipleChoiceBlock: () => ({ commands }) => {
        return commands.insertHTML('<multiple-choice></multiple-choice>')
      }
    }
  },
  parseHTML() {
    return [{ tag: 'multiple-choice' }]
  },
  renderHTML({ HTMLAttributes }) {
    return ['multiple-choice', mergeAttributes(HTMLAttributes)]
  },
  addNodeView() {
    return VueNodeViewRenderer(Component)
  }
})

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Reactions:2
  • Comments:5 (2 by maintainers)

github_iconTop GitHub Comments

3reactions
Hopiucommented, Apr 22, 2021

I have a similar use case, where I want to insert a specifically formatted title in combination with a paragraph. Is there a possibility to do this via a Component with multiple NodeViewContents?

0reactions
philippkuehncommented, Aug 11, 2021

The content of a node is always controlled by the content setting. A node view has nothing to do with that and renders always a single node.

Read more comments on GitHub >

github_iconTop Results From Across the Web

VueJS Components : Nested Components, Props and Directives
Components : · Step1: Remove the HelloWorld component from App.vue page · Step2: Create a component Navbar in the components folder · Step3:...
Read more >
How To Use Nested Routes in Vue.js - DigitalOcean
How To Use Nested Routes in Vue.js · Step 1 — Setting Up the Project · Step 2 — Building the Application ·...
Read more >
Nested vue.js instances/elements - Stack Overflow
Create a Vue instance on the body as you have above, but anything nested in that is a component. Pass data via props....
Read more >
Nested re-use of components - Get Help - Vue Forum
So, a -hopefully simple- question on re-using components in a looping ... Kid.vue'; export default { name: "child-node", props: ['node'], ...
Read more >
Vue recursive components: Rendering nested comments
To render our nested comments to the DOM, first, delete all the files in src/views and src/components . Then, create src/components/Comment.vue ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found