koopmac
koopmac

Reputation: 966

Stripe JS card element won't allow user input in Flask

I have used Stripe's Element example 1, found here: https://jsfiddle.net/ywain/2qyamjga/ to test Stripe Elements with Flask. In my app, the name and phone number fields allow user input but the card field does not.

Here is my code for the views function:

@billing.route('/charge', methods=['GET', 'POST'])
def charge():
    if request.method == 'POST':
        customer = stripe.Customer.create(
            email='[email protected]',
            source=request.form['stripeToken']
        )

        charge = stripe.Charge.create(
            customer=customer.id,
            amount=request.form['amountInCents'],
            currency='usd',
            description='Flask Charge'
        )
    return render_template('billing/charge.html')

After looking at the web console I'm receiving this error:

Error: The selector you specified (#card-element) applies to no DOM elements that are currently on the page. Make sure the element exists on the page before calling mount().

How would I go about doing this? Any suggestions would be greatly appreciated. The stripe source code can be found here: https://github.com/stripe/elements-examples/#example-1

Upvotes: 0

Views: 470

Answers (1)

koopmac
koopmac

Reputation: 966

After debugging I discovered the error was because my Javascript was before the html. The Javascript should be placed below the html for the form fields to work correctly:

<script src="https://js.stripe.com/v3/"></script>
<body>
  <form>
    <div class="group">
      <label>
        <span>Name</span>
        <input name="cardholder-name" class="field" placeholder="Jane Doe" />
      </label>
      <label>
        <span>Phone</span>
        <input class="field" placeholder="(123) 456-7890" type="tel" />
      </label>
    </div>
    <div class="group">
      <label>
        <span>Card</span>
        <div id="card-element" class="field"></div>
      </label>
    </div>
    <button type="submit">Pay $25</button>
    <div class="outcome">
      <div class="error"></div>
      <div class="success">
        Success! Your Stripe token is <span class="token"></span>
      </div>
    </div>
  </form>
</body>

<script>
var stripe = Stripe('pk_test_XXXXXXXXXXXXXXXX');
var elements = stripe.elements();

// Custom styling can be passed to options when creating an Element.
var style = {
  base: {
    // Add your base input styles here. For example:
    fontSize: '16px',
    color: "#32325d",
  }
};

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

      '::placeholder': {
        color: '#CFD7E0',
      },
    },
  }
});
card.mount('#card-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) {
    // Use the token to create a charge or a customer
    // https://stripe.com/docs/charges
    successElement.querySelector('.token').textContent = result.token.id;
    successElement.classList.add('visible');
  } else if (result.error) {
    errorElement.textContent = result.error.message;
    errorElement.classList.add('visible');
  }
}

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

document.querySelector('form').addEventListener('submit', function(e) {
  e.preventDefault();
  var form = document.querySelector('form');
  var extraDetails = {
    name: form.querySelector('input[name=cardholder-name]').value,
  };
  stripe.createToken(card, extraDetails).then(setOutcome);
});

</script>

Upvotes: 0

Related Questions