Stripe 'card-element' isn't visible (Python/Django)

Viewed 141

this is my first time using this site to ask a question. I'd appreciate the help, I have to turn in this bit of the project today as part of my course :(

I'm following this tutorial: https://www.youtube.com/watch?v=ncsCnC3Ynlw (chapter: stripe elements)

When I visit my checkout page, the card element isn't showing up.

I am at the stage around 3:45:00, and when looking at the checkout, the div for the card element is just a thin, empty bar.

Could anyone help me find where I made a mistake? I think it might be the connection between the script and the template or just the script itself, but I'm losing my mind trying to figure out what I've done wrong.

My views.py:

def BasketView(request):
    carrinho = Carrinho(request)
    total = str(carrinho.gettotal())
    total = total.replace('.', '')
    total = int(total)
    stripe.api_key='sk_test_[...]'
    intent = stripe.PaymentIntent.create(
        amount=total,
        currency='brl',
        metadata={'integration_check': 'accept_a_payment', 'userid': request.user.id}
    )
    return render(request, 'pedido/pedido_novo.html', {'client_secret': intent.client_secret})

My html template:

{% load static %}

{% block title %}Livraria Aquaflora | Novo Pedido{% endblock %}

{% block adtscripts %}
<script src="https://js.stripe.com/v3/"></script>

<script src="https://unpkg.com/imask@6.0.7/dist/imask.js"></script>

<script src="{% static 'js/orderform.js' %}"></script>

<script src="{% static 'js/payment.js' %}" data-rel-js></script>

{% endblock %}



{% block conteudo %}

<div class="container-fluid">
  <div class="row no-gutter">
    <div class="col-md-12">
      <div class="login d-flex align-items-center py-5">
        <div class="container">
          <div class="row">
            <form id="payment-form" class="col-12 col-lg-6 mx-auto">
              <div class="form-group">
                <label class="small font-weight-bold">Nome</label>
                <input type="text" class="form-control" id="custName" placeholder="Nome Completo" required>
              </div>
              <div class="form-group">
                <label class="small font-weight-bold">CPF</label>
                <input type="text" class="form-control" id="cpf" placeholder="CPF" required>
              </div>
              <div class="form-group">
                <label class="small font-weight-bold">CEP</label>
                <input type="text" class="form-control" id="cep" placeholder="CEP" required>
              </div>
              <div class="form-group">
                <label class="small font-weight-bold">Endereço</label>
                <input type="text" class="form-control" id="ender" placeholder="Endereço com Número e complemento" required>
              </div>
              <div class="form-group">
                <label class="small font-weight-bold">Bairro</label>
                <input type="text" class="form-control" id="bairro" placeholder="Bairro" required>
              </div>
              <div class="form-group">
                <label class="small font-weight-bold">Cidade</label>
                <input type="text" class="form-control" id="cidade" placeholder="Cidade" required>
              </div>
              <div class="form-group">
                <label class="small font-weight-bold">Estado</label>
                <input type="text" class="form-control" id="estado" placeholder="Estado" required>
              </div>
              
              <hr class="my-4">
              <h4 class="mb-3">Pagamento</h4>
              
              <hr class="my-4">

              <div id="payment-element" class="form-control form-control-payment">
              
              </div>
              <button id="submit" class="btn btn-primary btn-block py-2 mb-4 mt-5 fw500 w-100" data-secret="{{ client_secret }}">Pagar</button>
              
            </form>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<script>
    var CSRF_TOKEN = '{{ csrf_token }}';
</script>


{% endblock %}

and finally, my script,

var stripe = Stripe('pk_test_[...]');

var elem = document.getElementById('submit');
clientsecret = elem.getAttribute('data-secret');

var elements = stripe.elements();
var style = {
base: {
  color: "#000",
  lineHeight: '2.4',
  fontSize: '16px'
    }
};

var card = elements.create("card", { style: style });
card.mount("#card-element");

card.on('change', function(event) {
var displayError = document.getElementById('card-errors')
if (event.error) {
  displayError.textContent = event.error.message;
  $('#card-errors').addClass('alert alert-info');
} else {
  displayError.textContent = '';
  $('#card-errors').removeClass('alert alert-info');
}
});
2 Answers

I figured it out. Leaving it here for other dummies like me.

Do not add the .js file to the top of the page. Add it to the bottom, after the /body tag. Turns out values will be NULL if the javascript loads before the page.

The Python code looks correct, at least it looks like mine does in my working integration using Django. So here's a couple of things to try:

  1. You don't need the clientSecret until you use stripe.confirmCardPayment() so don't fetch it yet.
  2. Try putting the data-secret="{{client_secret}}" on the <form> element. You'll need to add an events listener to the <form>'s "submit" event anyway to prevent the default submission and trigger the confirmation so might as well retrieve the client_secret then.

I know this doesn't answer why the button was no selectable but at least it gives you some next steps.

Related