35

Instead of using the element type 'card' I needed to separate the elements, In the documentation example they only use 'card' so when they create a token they just pass the card object to the create token parameter.

stripe.createToken(card).then(function(result) {

});

How can I pass these multiple objects to create a token?

var cardNumber = elements.create('cardNumber');
cardNumber.mount('#card-number');
var cardExpiry = elements.create('cardExpiry');
cardExpiry.mount('#card-expiry');
var cardCvc = elements.create('cardCvc');
cardCvc.mount('#card-cvc');
var cardPostalCode = elements.create('postalCode');
cardPostalCode.mount('#card-postal-code');
Biskwit
  • 519
  • 1
  • 5
  • 11
  • I don't think there's such a thing as `stripe.createToken()`, just `stripe.card.createToken` and `stripe.bankAccount.createToken()` – Barmar Mar 22 '17 at 21:21
  • I don't recognize any of the methods you're using from [stripe.js documentation](https://stripe.com/docs/stripe.js?) – Barmar Mar 22 '17 at 21:23
  • I'm talking about this https://stripe.com/docs/elements/reference#stripe-create-token – Biskwit Mar 22 '17 at 21:27

2 Answers2

48

From the Elements reference.

element: the Element you wish to tokenize data from. The Element will pull data from other Elements you’ve created on the same instance of elements to tokenize.

https://stripe.com/docs/elements/reference#stripe-create-token

So you can initialize elements

var elements = stripe.elements();

And then define / mount your fields

var cardNumber = elements.create('cardNumber');
cardNumber.mount('#card-number');
var cardExpiry = elements.create('cardExpiry');
cardExpiry.mount('#card-expiry');
var cardCvc = elements.create('cardCvc');
cardCvc.mount('#card-cvc');

// creating a postal code element is deprecated 
// var cardPostalCode = elements.create('postalCode');
// cardPostalCode.mount('#card-postal-code');

Then this should pull them all in as they are part of elements

stripe.createToken(cardNumber).then(doSomething);

Edit: The postal code element has been deprecated, so I removed it from my example. If you're using separate fields and want to collect the postal code (or other address data), you should do this via an <input> and then pass it into the optional cardData object when calling stripe.createToken

https://stripe.com/docs/stripe-js/reference#elements-create

// <input id="postal-code" name="postal_code" class="field" placeholder="90210" />

var cardData = { 
  address_zip: document.getElementById('postal-code').value
}

stripe.createToken(cardNumber,cardData).then(doSomething);
duck
  • 5,240
  • 1
  • 15
  • 15
  • 2
    Shouldn't it be `stripe.createToken(elements)`? – Barmar Mar 22 '17 at 21:46
  • 2
    It has to be one of the elements you've created and mounted rather than the parent `elements` here --- `stripe.createToken(elements)` will throw an error. – duck Mar 22 '17 at 21:51
  • 1
    So he has to call `createToken` separately for each element? – Barmar Mar 22 '17 at 21:52
  • 8
    @Barmar nope! On any one of the elements will work. https://jsfiddle.net/ywain/o2n3js2r/ – duck Mar 22 '17 at 22:47
  • Thx. We're still using stripe.js v2, I'm not really familiar with this new design. – Barmar Mar 22 '17 at 22:48
  • 4
    Thanks a lot. I could not figure how to create the token with cardNumber only but indeed `stripe.createToken(cardNumber)` works ! Stripe's docs would need improvements regarding Elements' customization... – Julien Salinas Jun 30 '17 at 09:09
  • 3
    this approach works thanks. But I agree, it is not a very intuitive approach to creating an API. If anyone here works for Stripe, could you please take a look at this – Kesupile K Jul 28 '17 at 09:33
  • wtf, in v2 you could pass in a object, now you have to use there own UI elements too? sucks – Endless Nov 28 '17 at 19:17
3

Here is a jsfiddle someone from the Stripe team put together that takes a different approach:

https://jsfiddle.net/ywain/o2n3js2r/

var stripe = Stripe('XYZ');
var elements = stripe.elements();

var style = {
  base: {
    iconColor: '#666EE8',
    color: '#31325F',
    lineHeight: '40px',
    fontWeight: 300,
    fontFamily: 'Helvetica Neue',
    fontSize: '15px',

    '::placeholder': {
      color: '#CFD7E0',
    },
  },
};

var cardNumberElement = elements.create('cardNumber', {
  style: style
});
cardNumberElement.mount('#card-number-element');

var cardExpiryElement = elements.create('cardExpiry', {
  style: style
});
cardExpiryElement.mount('#card-expiry-element');

var cardCvcElement = elements.create('cardCvc', {
  style: style
});
cardCvcElement.mount('#card-cvc-element');

var postalCodeElement = elements.create('postalCode', {
  style: style
});
postalCodeElement.mount('#postal-code-element');


function setOutcome(result) {
  var successElement = document.querySelector('.success');
  var errorElement = document.querySelector('.error');
  successElement.classList.remove('visible');
  errorElement.classList.remove('visible');

  if (result.token) {
    // In this example, we're simply displaying the token
    successElement.querySelector('.token').textContent = result.token.id;
    successElement.classList.add('visible');

    // In a real integration, you'd submit the form with the token to your backend server
    //var form = document.querySelector('form');
    //form.querySelector('input[name="token"]').setAttribute('value', result.token.id);
    //form.submit();
  } else if (result.error) {
    errorElement.textContent = result.error.message;
    errorElement.classList.add('visible');
  }
}

cardNumberElement.on('change', function(event) {
  setOutcome(event);
});

document.querySelector('form').addEventListener('submit', function(e) {
  e.preventDefault();
  stripe.createToken(cardNumberElement).then(setOutcome);
});
cman77
  • 1,753
  • 1
  • 22
  • 48
  • How is this different from duck's solution? Seems like it is creating a token from the card number element as well. – ricks Feb 11 '19 at 21:38