Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular Stripe - Converting Stripe Payment Form to Stripe Elements

I used to have Angular Stripe Checkout form and I am trying to update my form to the new Stripe Card Elements which was introduced recently.

After removing the Form Input fields and replacing them with the Stripe Card element, my form looks like this:

<form name="payment" ng-submit="vm.submit()">
<div class="row">
    <label for="card-element">
      Credit or debit card
    </label>
    <div id="card-element">
      <!-- a Stripe Element will be inserted here. -->
    </div>
</div>
<button class="btn btn-primary" type="submit" ng-disabled="vm.submitting">Pay!</button>
<div ng-show="vm.cardError" class="row">
  <div class="has-error">
     <p class="help-block">* {{vm.cardError}}</p>
  </div>
</div>
</form>

Previously in Angular, when the form is submitted, I was handling the submit() and stripeResponseHandler from the controller. After updating my Angular Controller with the new changes, my controller now looks like this:

function PaymentController() {
        var vm = this;
        var elements = stripe.elements();
        var style = {
                          base: {
                            color: '#32325d',
                            lineHeight: '24px',
                            fontFamily: 'Helvetica Neue',
                            fontSmoothing: 'antialiased',
                            fontSize: '16px',
                            '::placeholder': {
                              color: '#aab7c4'
                            }
                          },
                          invalid: {
                            color: '#fa755a',
                            iconColor: '#fa755a'
                          }
                     };
        vm.card = elements.create('card', {style: style});
        vm.card.mount('#card-element');

        // Handle real-time validation errors from the card Element.
        vm.card.addEventListener('change', function(event) {
              if (event.error) {
                vm.cardError = event.error.message;
              } else {
                vm.cardError = '';
              }
        });

        function submit() {
            vm.cardError = '';
            vm.submitting = true;
            createToken();
        }

        // Send data directly to stripe 
        function createToken() {
            stripe.createToken(vm.card).then(function(result) {
              if (result.error) {
                vm.cardError = result.error.message;
                vm.submitting = false;
              } else {
                // Send the token to your server
                stripeTokenHandler(result.token);
              }
            });
        }

        // Response Handler callback to handle the response from Stripe server
        function stripeTokenHandler(token) {
            vm.tokenData = {
                token: token.id
            };
            .. Process the rest in server ...
        }
}

The above code works as is. But I am confused on these:

1) Since Stripe now uses DOM Manipulation to insert the card elements inside the form, does that make my above method wrong as in Angular way? Meaning, should I not be doing these in Controller anymore and move them to a directive instead? Or should that not be necessary since the element manipulated is using stripe.elements().

2) If I do need to have them inside directive, I am just not sure how to convert the above to an angular directive. It first manipulates the element by mounting it (which can be added to the directive link function), but later it goes on to use the card element for form submit and event handlers. Do I need to do all this inside the directive link itself of have the submits inside directive controller and the element manipulation in link?

I am so confused and stuck on what to do here. Can someone give me a sample on how I can address this if I am doing it wrong please?

I am using Angular 1.5.

like image 404
Neel Avatar asked Feb 21 '17 07:02

Neel


People also ask

Is there any way to prefill payment information in Stripe elements?

No, by design you cannot prefill payment information in Stripe Elements.

How do I customize a Stripe payment form?

Apply branding You can customize the look and feel of Checkout in the Stripe Dashboard. Go to Branding Settings where you can: Upload a logo or icon. Customize the Checkout page's background color, button color, font, and shapes.

Is Stripe checkout deprecated?

Is Stripe checkout deprecated? Stripe will not be updating the Stripe Checkout modal to comply with Strong Customer Authentication (SCA) and as a result they no longer recommend using that integration.


1 Answers

I have now changed the Controller to a directive and placed all the jquery and angular codes inside the Link function. This is how my directive code looks like after the update:

function stripeForm() {

        // Link Function
        function link(scope, element, attrs) {

            scope.submitCard = submitCard;

            var elements = stripe.elements();
            var style = {
                          iconStyle: 'solid',
                          style: {
                            base: {
                              iconColor: '#8898AA',
                              color: '#000',
                              lineHeight: '36px',
                              fontWeight: 300,
                              fontFamily: 'Helvetica Neue',
                              fontSize: '19px',

                              '::placeholder': {
                                color: '#8898AA',
                              },
                            },
                            invalid: {
                              iconColor: '#e85746',
                              color: '#e85746',
                            }
                          },
                          classes: {
                            focus: 'is-focused',
                            empty: 'is-empty',
                          },
                        };
            var card = elements.create('card', style);
            card.mount('#card-element');

            // Handle real-time validation errors from the card Element.
            card.on('change', function(event) {
                setOutcome(event);
            });

            // Form Submit Button Click
            function submitCard() {
                var errorElement = document.querySelector('.error');
                errorElement.classList.remove('visible');
                createToken();
            }

            // Send data directly to stripe server to create a token (uses stripe.js)
            function createToken() {
                stripe.createToken(card).then(setOutcome);
            }

            // Common SetOutcome Function
            function setOutcome(result) {
                var errorElement = document.querySelector('.error');
                errorElement.classList.remove('visible');
                if (result.token) {
                  // Use the token to create a charge or a customer
                  stripeTokenHandler(result.token);
                } else if (result.error) {
                  errorElement.textContent = result.error.message;
                  errorElement.classList.add('visible');
                }
            }

            // Response Handler callback to handle the response from Stripe server
            function stripeTokenHandler(token) {
                ..send to server ...
            }
        }

        // DIRECTIVE
        return {
            restrict: 'A',
            replace: true,
            templateUrl: 'payment/PaymentForm.html'
            link: link
        }
    }

My HTML File is now like this:

<form ng-submit="submitCard()">
    <div>
      <label>
        <div id="card-element" class="field"></div>
      </label>
    </div>
    <div>
        <button class="btn btn-primary pull-right" type="submit">Pay!</button>
        <button class="btn btn-danger pull-left" type="button" ng-click="cancel()">Cancel</button>
    </div>
    <div>
      <div class="error"></div>
    </div>
</form>
like image 86
Neel Avatar answered Sep 19 '22 04:09

Neel