Luiz Alves
Luiz Alves

Reputation: 2645

Insert and modify a script tag inside template Vue

I'm creating a integration with a payment service. The payment service provides me a form with a script tag inside.

My question is a continuation from Insert a script tag inside template Vue

The form with checkout of payment service:

<form action="http://localhost:8081/api/v1/payment/" method="POST">
      <script
        src="https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js"
        data-public-key="KEY"
        data-transaction-amount="14.90">
      </script>
</form>

I can make the next on "mounted()" of vuejs:

<form ref="myform">
  ...
</form>

mounted() {
  let foo = document.createElement('script');    
  foo.setAttribute("src","https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js");
  foo.setAttribute("data-transaction-amount", this.newAmount)
  this.$refs.myform.appendChild(foo);
}

But, my problem is that after the view has been mounted. the user can change "data-transaction-amount".

To solve it , I tried:

data:()=>({
  newAmount:0
})

watch: {
    newAmount() {
      this.modifyScript();
    },
  },
  methods: {
    modifyScript() {
      let scripts = document.getElementsByTagName("script");
      for (let i = 0; i < scripts.length; i++) {
        let script = scripts[i];
        if (script.getAttribute("src") == 'https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js') {
          // we've got a match
          script.setAttribute("data-transaction-amount", this.newAmount);
        }
      }
    },

The "data-transaction-amount" is changing to new value, but the window checkout of payment service shows the original value used in "mounted()".

Upvotes: 0

Views: 1196

Answers (1)

Sphinx
Sphinx

Reputation: 10729

One solution should be let the browser force to reload the javascript file after the amount is changed.

Below is one steps:

  1. adds one version# into the end of the URL
  2. when amount is changed, removes the script element (src=...?old_amount) already added before
  3. adds new script element (src=...?new_amount)

Below is one fiddle (open the browser console, then you will see the script web-tokenize-checkout.js is redownloaded when the amount is changed).

Vue.component('v-loadjs',{
    template:`
        <div>
            <p><button class="btn btn-info" v-on:click="changeAmount()">Change Amount: {{amount}}</button></p>
            <p ref="test"></p>
        </div>
    `,
    data () {
      return {
        amount: 0,
        url: 'https://www.mercadopago.com.br/integrations/v1/web-tokenize-checkout.js'
      }
    },
    mounted: function () {
      this.loadJS(this.amount, this.amount)
    },
    watch: {
      amount: function(newAmount, oldAmount) {
        this.loadJS(newAmount, oldAmount)
      }
    },
    methods: {
      changeAmount: function () {
        this.amount += 1
      },
      loadJS: function (newAmount, oldAmount) {
        [...document.querySelectorAll('button.mercadopago-button')].forEach(item => item.remove())
        let scripts = document.getElementsByTagName("script");
        for (let i = 0; i < scripts.length; i++) {
          if (scripts[i].getAttribute("src") == this.url + '?version=' + oldAmount) {
            scripts[i].remove()
          }
        }
        let foo = document.createElement('script');    
        foo.setAttribute("src", this.url + '?version=' + newAmount);
        foo.setAttribute("data-transaction-amount", newAmount)
        this.$refs.test.appendChild(foo);
      }
    }
})

new Vue ({
  el:'#app'
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
    <div class="container">
        <div class="col-lg-offset-4 col-lg-4">
            <v-loadjs></v-loadjs>
        </div>
    </div>
</div>

Upvotes: 2

Related Questions