1

I have a simple vue instance that I'm using to generate a Stripe token.

It looks like this:

var vm = new Vue({
        el: '#checkout-form',
        data: {
            stripe_publishable_key: '{{ config('services.stripe.publishable') }}',
            card: {
                number: null,
                cvc: null,
                exp: null,
            },
        },
        ready: function() {    
            Stripe.setPublishableKey(this.stripe_publishable_key);
        },
        methods: {
            getStripeToken: function() {
                Stripe.card.createToken(this.card, this.stripeResponseHandler);
            },
            stripeResponseHandler: function(status, response) {
                // Process response
            },
        },       
    });

Basically I pass the card object in my Vue instance (which is bound to some form inputs) to Stripe's card.createToken method. This should take the input and call the handler, passing in the response as it does so.

This all works fine except that card.createToken is modifying the card object and causing the card object on my Vue instance to change - it inserts its own properties and causes strange behaviour on the bound <inputs>.

Is there a way to pass the card vue property to Stripe as a copy which is unbound to the vue instance and thus won't change as a result?

Update

In essence this is happening because JavaScript passes objects as a copy-of-a-reference which means the original object can be modified by any function that receives it. The obvious solution is to clone the object by looping or some other means but I was wondering if there's a better way in Vue.

Community
  • 1
  • 1
harryg
  • 23,311
  • 45
  • 125
  • 198

4 Answers4

5

There are many ways to make a copy of this object, but only one from Vue itself:

var cardCopy = Vue.util.extend({}, this.card);

It is actually an equivalent to jQuery's extend with deep set to true.

oleh.meleshko
  • 4,675
  • 2
  • 27
  • 40
1

Not that I know much Vie.js but is this.data is simply a JavaScipt object then you could clone it with this:

function cloneObject(obj) {
  var clone = {};
  Object.keys(obj).forEach(function(key) {
    clone[key] = obj[key];
  });
  return clone;
}

Or in ES3 land:

function cloneObject(obj) {
  var key, clone = {};
  for (key of obj) {
    if (obj.hasOwnProperty(key) {
      clone[key] = obj[key];
    }
  }
  return clone;
}

But this is a shallow clone so objects that are properties of the obj would not be cloned but their references would be the same (allowing mutation).

jQuery (if you have that) also provides a convenient way to do this:

var clone = $.extend({}, this.data);

And finally as @oleg-melashko pointed out Vue.js has a Vue.util.extend as well (though the documentation seems to lack any reference to this).

var clone = Vue.util.extend({}, this.data);
Sukima
  • 9,965
  • 3
  • 46
  • 60
1

You can also copy the card object like below

let cardCopy = JSON.parse(JSON.stringify(this.card));
Shehan Rangana
  • 360
  • 6
  • 9
0

There is coerce hook function for properties in Vue 1.0.12

It can be used for creation of object clone like that (ES6)

import _ from 'lodash';
export default{
    props: {
        myObjProp: {
            type: Object,
            coerce(val) {
                return _.clone(val);
            }
        }
    }
};
Yegor
  • 525
  • 6
  • 6