Search code examples
javascriptvuejs2html-object

Render [object HTMLTableElement] in VueJS


for those of you that have tried jsdifflib know that this plugin returns an HTMLTableElement. Right now I want to try to render/display this on my VueJS component.

I've tried the following:

TEMPLATE

<div class="diff-container" v-html="dynamicHtmlContent" ref="auditContainer"></div>

COMPONENT

export default {
    name: 'AuditView',
    data() {
      return {
        dynamicHtmlContent: null
      }
    },
    created() {
      // code logic here and there
      this.processDataDiff(results, 0);
    },
    methods: {
      processDataDiff: function (data, index) {
        // code logic here and there
        this.displayDiff(
          JSON.stringify(object1, null, 4).replace(/\\n/g, '\n'),
          JSON.stringify(object2, null, 4).replace(/\\n/g, '\n'),
          versionId1,
          versionId2
        );
      },
      displayDiff: function (baseDoc, newDoc, baseVersion, newVersion) {
        this.dynamicHtmlContent = auditService.getDiff(baseDoc, newDoc, baseVersion, newVersion);
      }
    }
}

ES6 service

 getDiff(baseTextRaw, newTextRaw, baseVersion, nextVersion) {
   // build the diff view and return a DOM node
   return difflib.buildView({
     baseText: baseTextRaw,
     newText: newTextRaw,
     // set the display titles for each resource
     baseTextName: 'Version ' + baseVersion,
     newTextName: 'Version ' + nextVersion,
     contextSize: 10,
     // set inine to true if you want inline
     // rather than side by side diff
     inline: false
   });
 }

I've skipped the code logic but I already checked the dynamicHtmlContent and this returns to as an HTML Object as seen on the screenshot below:

Screenshot

Somehow this isn't possible using v-html as it only renders an object {} as said on console.log(typeof this.dynamicHtmlContent); So how do I render this to my Vue Component? I also find this hard to convert into a plain string. Please help me on this.


Solution

  • You can still use v-html you just have to change what you are accessing. Since what you get back is going to end up being an actual DOM element you can do a couple of things.

    The first is to simply change v-html to access the outerHTML property of your element

    v-html="dynamicHtmlContent.outerHTML"
    

    Or save outerHTML directly to dynamicHtmlContent instead of the DOM element

    this.dynamicHtmlContent = auditService.getDiff().outerHTML
    

    The other thing you can do is directly append the DOM element by accessing your auditContainer reference through this.$refs

    displayDiff: function (baseDoc, newDoc, baseVersion, newVersion) {
      var table = auditService.getDiff(baseDoc, newDoc, baseVersion, newVersion);
      this.$refs.auditContainer.appendChild( table );
    }
    

    Note though this would have to be done after the component has been mounted as the auditContainer will not have been created yet. Meaning:

    created() {
      // code logic here and there
      this.processDataDiff(results, 0);
    },
    

    would be changed to:

    mounted() {
      // code logic here and there
      this.processDataDiff(results, 0);
    },
    

    v-html Demo

    var table = document.createElement('table');
    var body = table.createTBody();
    var row = body.insertRow();
    var cell = row.insertCell();
    cell.innerHTML = "A test table";
    
    var vm = new Vue({
      el: '#app',
      data() {
        return {
          dynamicHtmlContent: null
        }
      },
      created() {
        this.displayDiff();
      },
      methods: {
        displayDiff: function() {
          this.dynamicHtmlContent = table;
        }
      }
    });
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <div id="app">
      <div class="diff-container" v-html="dynamicHtmlContent.outerHTML" ref="auditContainer"></div>
    </div>

    DOM append Demo

    var table = document.createElement('table');
    var body = table.createTBody();
    var row = body.insertRow();
    var cell = row.insertCell();
    cell.innerHTML = "A test table";
    
    var vm = new Vue({
      el: '#app',
      data() {
        return {
          dynamicHtmlContent: null
        }
      },
      mounted() {
        this.displayDiff();
      },
      methods: {
        displayDiff: function() {
          this.$refs.auditContainer.appendChild(table);
          
        }
      }
    });
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
    <div id="app">
      <div class="diff-container" ref="auditContainer"></div>
    </div>