-2

What i'm trying to do is have a root element with a prop that holds inner html like: hello<b>hey</b> but i can't use v-html because this element also has children for example:

<template>
  <component :is="element.tag" contenteditable="true">
    <div contenteditable="false">
      <span class="delete-obj" :id="'delete'+element.id" >delete</span>
    </div>
    <RenderString :string="element.content" />
  </component>
</template>
<script>
    import Vue from "vue";
  
    Vue.component("RenderString", {
        props: {
            string: {
                required: true,
                type: String
            }
        },
        render(h) {
            const render = {
                template:  this.string ,
                methods: {
                    markComplete() {
                        console.log('the method called')
                    }
                }
            }
            return h(render)
        }
    })
    export default {
        name: "VElement",
        props: {
            element: {
                required: false,
                default: null
            },
        },
    }
 </script>

I have tried the above and I have tried using slots. I can solve it with vanilla JavaScript like element.innerText, but I don't want to. The main goal is that the element is editable when they type they are editing element.content that will be rendered and the div that's inside it is normal HTML that I also need. The main problem is that the inner HTML that I want doesn't have a root element. The element is something like:

{id:1,tag:"div",content:"hello<b>hey</b>"}

I want the final result to be:

<div contenteditable="true">
    <div contenteditable="false">
        <span class="delete-obj" :id="'delete'+element.id" >delete</span>
    </div>
    hello<b>hey</b>
<div>

And I want to edit hello<b>hey</b> when I click inside I don't want it wrapped in anything else and if I put v-html on the outer div the inner div is gone.

karel
  • 5,489
  • 46
  • 45
  • 50
Girl Codes
  • 328
  • 4
  • 17

2 Answers2

2

If you really aren't able to wrap the content in a parent element, maybe a good approach is to write a VUE directive that render the text.

JS FIDDLE FULL DEMO

//DIRECTIVE
Vue.directive('string', {
    inserted(el, bind) {
        /** 
        * Here you can manipulate the element as you need.
        */

        el.insertAdjacentText('beforeend', bind.value); 
    }
});

//TEMPLATE
<template>
  <component :is="element.tag" contenteditable="true" v-string="element.content">
    <div contenteditable="false">
      <span>delete</span>
    </div>
  </component>
</template>
tony19
  • 125,647
  • 18
  • 229
  • 307
The.Bear
  • 5,621
  • 2
  • 27
  • 33
1

Like Seblor said, v-html will work with nested html strings.

Simply replacing the RenderString component with a <div v-html="element.content"/> should get you what you want.

Tested with the given example of hello<b>hey</b>:

Vue.component('VElement', {
  name: "VElement",
  props: {
    element: {
      required: false,
      default: null
    },
  },
  template: '\
    <component :is="element.tag" contenteditable="true">\
      <div contenteditable="false">\
        <span class="delete-obj" :id="\'delete\'+element.id">delete</span>\
      </div>\
      <div v-html="element.content"/>\
    </component>'
})

new Vue({
  el: '#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <v-element :element="{id:1, tag:'div', content:'hello<b>hey</b>'}" />
</div>
TUTAMKHAMON
  • 600
  • 3
  • 9
  • My problem is that i dont want the element.content to be inside the inner div i want it to be directly in the parent div not wrapped inside and if i use v-html on the outer div the div thats inside is gone – Girl Codes May 02 '21 at 09:55