Search code examples
javascriptvue.jsvirtual-dom

How to update Vue data to reflect changes in the HTML made by user input


I'm using Vue for a small application that copies a piece of dynamic HTML to the user's clipboard after they filled in a form. All works well but I can't seem to reflect changes in the HTML after I have executed the copy method once. I feel like there is something about the virtual DOM that I haven't quite understood and it hinders me finding a solution to the problem.

This is the Vue js:

var app = new Vue({
  delimiters: ['${', '}'], // Alternative delimiters for Twig+Vue
  el: '#app',
  data: {
    lastname: null,
    firstname: null,
    mailto: null,
    occupation: 'Consultant',
    absoluteurl: absBaseUrl,
    companyId: 9, // Default company ID
    companies: []
  },
  computed: {
    logo() {
      return this.absoluteurl + companies[this.companyId].logo;
    },
    setMailto() {
      return 'mailto:' + this.mailto;
    },
    input() {
      return this.$refs.signaturepreview.innerHTML;
    }
    // signatureBanner() {
    //   if (companies[this.companyId].)
    //   return companies[this.companyId].logo;
    // }
  },
  methods: {
    changeComp: function() {
      console.log('company select input changed');
    },
    copyToClipboardFF: function(text) {
      window.prompt ("Copy to clipboard: Ctrl C, Enter", text);
    },
    copySignature: function() {
      // console.log(this.input);
      var success   = true,
          range     = document.createRange(),
          selection;
      // For IE.
      if (window.clipboardData) {
        window.clipboardData.setData("Text", this.input);
      } else {
        // Create a temporary element off screen.
        var tmpElem = $('<div>');
        tmpElem.css({
          position: "absolute",
          left:     "-1000px",
          top:      "-1000px",
        });
        // Add the input value to the temp element.
        tmpElem.text(this.input);
        $("body").append(tmpElem);
        // Select temp element.
        range.selectNodeContents(tmpElem.get(0));
        selection = window.getSelection ();
        selection.removeAllRanges ();
        selection.addRange (range);
        // Lets copy.
        try {
          success = document.execCommand ("copy", false, null);
        }
        catch (e) {
          this.copyToClipboardFF(this.input.val());
        }
        if (success) {
          alert ("Signature is copied to the clipboard!");
          // remove temp element.
          tmpElem.remove();
        }
      }
    }
  },
  mounted() {
  this.companies = companies; // Get json data in the Vue instance
}
})

The relevant part is the computed data input(), and the method copySignature.

And the HTML looks something like this:

<div ref="signaturepreview" id="signature-preview" class="preview-wrapper signature-preview">

  <table class="signature" style="
    All sorts of info fetched from a form with jQuery
  </table>
</div>


<button id="validate-signature" class="button button--green" @click="copySignature">Je valide ma signature</button>

When the button is clicked the input data should be refreshed every time, but it only works once. After that the content on the clipboard just stays the same whatever I do.


Solution

  • You have defined input as a computed, but it does not reference anything reactive, so its value never gets updated. If you use a method instead, it will be evaluated every time it is called, and you will get the current value.