Search code examples
javascriptvue.jscontenteditable

contenteditable div append a html element and v-model it in Vuejs


Here is my Html code.

<div id="app">

  <button @click="renderHtml">clisdfsdfsdfck to appen html</button>
  <div class="flex">
      <div class="message" @input="fakeVmodel" v-html="html" contenteditable="true"></div>
      <div class="message">{{ html }}</div>
  </div>
</div>

Here is js part

let app = new Vue({
    el: '#app',
    data: {
        html: 'some text',
    },
    methods: {
        fakeVmodel: function(e){
            this.html = e.target.innerText;
        },
        renderHtml: function(){
          this.html += '<img src="https://cdn-images-1.medium.com/max/853/1*FH12a2fX61aHOn39pff9vA.jpeg" alt="" width=200px>';
        }
    }
});

The problem is, when I click the button to push a html tag(img) to my variable (html) and it works. but after typing, it will remove the tag part that was insert. Is that any way to append to html code successful in Vue?

Here is the codepen example https://codepen.io/weretyc/pen/EwXZYL?editors=1010


Solution

  • The main problem: The html disappears because of this.html = e.target.innerText;. Instead, use this.html = e.target.innerHTML;. innerHTML resolves to the full HTML content.

    Secondary Problem: After typing, the cursor focuses the beginning of the div. This is because v-html causes the div to update.

    To solve, ensure that v-html only updates the div on focusout.

    Full Example

    let app = new Vue({
      el: '#app',
      data: {
        html: 'some text',
      },
      methods: {
        updateHtml: function(e) {
          this.html = e.target.innerHTML;
        },
        renderHtml: function(){
          this.html += '<img src="https://cdn-images-1.medium.com/max/853/1*FH12a2fX61aHOn39pff9vA.jpeg" alt="" width=200px>';
        }
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.js"></script>
    <div id="app">
     
      <button @click="renderHtml">click to append html</button>
      <div class="flex">
          <div class="message" @focusout="updateHtml" v-html="html" contenteditable="true"></div>
          <br>
          <div class="message">{{ html }}</div>
      </div>
    </div>