What is the best way to utilize an AngularJS directive to send a POST request with all parameters from a form?

I have created a custom AngularJS form with Stripe integration using a directive. You can view the Fiddle for this project here: https://jsfiddle.net/u5h1uece/.

HTML:

<body ng-app="angularjs-starter">
  <script src="https://js.stripe.com/v3/"></script>
  <div ng-controller="MainCtrl">
    <form name="regForm" id="register-form">
      <label>Email</label>
      <input ng-model="reg.email" type="email" name="username">
      <div stripe-validator 
           stripe-complete="stripeCompleted" 
           stripe-form-id="register-form"></div>
      <br>
      <button ng-model="reg.btn" ng-disabled="stripeCompleted === false || !regForm.username.$valid">Register</button>
    </form>
  </div>
</body>

JS:

var app = angular.module('angularjs-starter', []);

app.controller('MainCtrl', function($scope, $rootScope) {
  //Initialize stripe state within the controller
  $scope.stripeCompleted = false;
});


app.directive('stripeValidator', function() {
  return {
    restrict: 'A',
    template: `
      <div id="stripe-wrapper">
        <div id="card-element"></div>
      </div>
      <small id="card-errors" class="text-danger" role="alert">{{ ccErrMsg }}</small>
      <input type="hidden" name="stripeToken" ng-value="stripeToken" />`,
    scope: {
      "stripeComplete": '=',
      "stripeFormId": '@',
      "stripeError": '=',
      "stripeToken": '=',
    },
    link: function(scope, element, attrs) {

      //Initialization
      var stripe = Stripe("pk_test_6pRNASCoBOKtIshFeQd4XMUh");
      var elements = stripe.elements();
      var card = elements.create("card");
      var form = document.getElementById(scope.stripeFormId);

      //Mount the card element https://stripe.com/docs/stripe-js/reference#element-mount
      card.mount("#card-element");

      //Add event listener
      card.addEventListener('change', function(event) {

        //Check for errors
        if (event.error) {
          scope.ccErrMsg = event.error.message;
        } else {
          scope.ccErrMsg = '';
        }

        //Check for completion
        scope.stripeComplete = event.complete ? true : false;

        //Apply scope
        scope.$apply();
      });

      //Inject form submit event
      form.addEventListener("submit", function(event) {

        //Prevent default form submission
        event.preventDefault();

        //Handle token creation, error handling, and form submission forwarding
        stripe.createToken(card).then(function(result) {

          if (result.error) {
             scope.ccErrMsg = event.error.message;
             scope.stripeToken = '';
          } else {
             scope.ccErrMsg = '';
             scope.stripeToken = result.token;
          }

          //Apply scope
          scope.$apply();

          //Forward the form submit
          form.submit();
        })
      });
    }
  }
});

Rather than using form.submit(), I would like to utilize $http.post() to send the form data to my backend, then handle the response data within a .then() function. The parameters to be sent include the value of reg.email.

How can I achieve this setup with my current form structure? I prefer to use ng-submit, but if that is not feasible, is there an alternative approach?

Answer №1

To enhance the functionality of the stripe input field, I recommend utilizing a custom component. This component can interact with the parent scope through the ng-model directive and enable form validation for the stripe input.

If you prefer a concise demonstration, here is an example Fiddle: Example Fiddle

Start by creating the stripe object as a service to facilitate sharing:

app.service('stripe', function () {
    return Stripe("pk_test_6pRNASCoBOKtIshFeQd4XMUh");
});

Subsequently, implement the stripe component to encapsulate the stripe input and incorporate customized ng-model validation:

app.component('stripe', {
    bindings: {
        state: '='
    },
    require: {
        model: 'ngModel'
    },
    controller: function ($element, $timeout, stripe) {
        this.$onInit = function () {
            var ctrl = this;

            // Utilize stripe elements within the controller
            var elements = stripe.elements();
            var card = elements.create('card');
            card.mount($element[0]);

            card.addEventListener('change', function (event) {
                ctrl.state = event; 
                
                ctrl.model.$setValidity('stripe', event.complete);

                if (event.complete) {
                    ctrl.model.$setViewValue(card);
                } else {
                    ctrl.model.$setViewValue(null);
                }
            });
        }
    }
});

In your main controller, generate the stripe token at form submission before proceeding with the HTTP request:

app.controller('MainCtrl', function ($scope, $http, stripe) {
    $scope.reg = {};
    $scope.onChange = function() {
        console.log($scope.card); 
    };
    $scope.register = function () {
        stripe.createToken($scope.card).then(function (result) {
            if (result.error) {
                console.error(result.error);
            } else {
                $scope.reg.stripeToken = result.token;
                $http.post('request-url', $scope.reg).then(function (response) {
                    console.log(response);
                }).catch(function (err) {
                    console.error(err);
                });
            }
        });
    };
});

You can easily insert a stripe element into your template:

<div ng-app="angularjs-starter" ng-controller="MainCtrl">
  <form name="regForm" id="register-form" ng-submit="register()">
    <stripe name="card" ng-model="card" state="cardState" ng-change="onChange()" ng-required="true"></stripe>
    <button ng-disabled="regForm.$invalid">Register</button>
    <span ng-if="regForm.card.$invalid">{{ cardState.error.message }}</span>
  </form>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why Are My JavaScript GET Request Parameters Displaying as Strings Rather Than Numbers?

Currently, I am in the process of developing a REST API where one of the defined routes looks like this: router.get("/objects/:id?/:val1?/:val2?", getObject); Specifically, my request from Postman appears as follows: http://localhost:8000/objects?val1= ...

Loading Datatables using PHP to send JSON data

I seem to be facing some difficulty in troubleshooting the issue within my code. Currently, I am working on a search script and would like to display the results using Datatables. I have a search form that sends data to my PHP file which then returns a JS ...

Upon clicking, the input texts revert to their original default values

I have a form below that is working as intended, except for one issue. When I click the 'Add' link, the texts in all the textboxes revert to their default values, as shown in the images. How can I resolve this problem? Thank you. before click: ...

I can't figure out why I'm receiving undefined even though all the variables are populated with the necessary

I have been working on a project that involves implementing email and password authentication using Firebase. However, I encountered an error when the user submits their credentials: FirebaseError: Firebase: Error (auth/admin-restricted-operation). at ...

What is the best way to design an angular directive or service specifically for straightforward pagination featuring only next and previous options?

Within a block of div tags, an ng-repeat directive is being used to display sets of 3 divs at a time. By clicking on the next button, the next set of 3 divs should be displayed, and the same goes for the previous button. Check out the HTML code below: &l ...

Postman post request failing to insert Mongoose model keys

Recently, I've been experimenting with the post method below to generate new documents. However, when I submit a post request in Postman (for example http://localhost:3000/api/posts?title=HeaderThree), a new document is indeed created, but unfortunate ...

Reverting to the original order in jQuery DataTables after dropping a row

Recently, I've been attempting to utilize jQuery DataTables in conjunction with the Row Ordering plugin. At first, everything seemed to be functioning properly until a javascript error popped up indicating an unrecognized expression. After researching ...

jQuery divs seem to "gaze up" towards the mouse pointer

I am attempting to recreate a fascinating effect using jQuery - where "cards" move in response to the mouse cursor as if they are looking up at it. I have come across a script that almost achieves what I need, but I require the ability to control the mov ...

employing async/await in the function of a backend API

I'm facing an issue with the following code snippet: service.js module.exports = { getUser }; async function getUser({ data }) { return new Promise((resolve, reject) => { const id = data["id"]; const doc = await db.colle ...

Hover over the div to center an SVG inside it

Simply put, I am working on a design where a gradient bar moves above a specific element when hovered, creating a visual effect of a triangle. I am now looking for a way to center an SVG inside the element on hover, to create a similar triangular gradient ...

How to extract the HTML content from specific text nodes using Javascript

I have a piece of HTML that looks like this: <div id="editable_phrase"> <span data-id="42">My</span> <span data-id="43">very</span> <span data-id="1">first</span> <span data-id="21">phrase< ...

The issue arises when trying to use destructured imports with Mongoose

I've been developing a straightforward Express app with ES6. In the process of creating a schema and model for Mongoose, I encountered an issue with the following syntax: import mongoose, { Schema } from 'mongoose'; const PostSchema = new ...

Tips for transferring a boolean value to a generic parameter in Java?

Looking to pass a boolean value to the Generic type in order to be utilized within a condition. This is the generic type interface OptionTypeBase { [key: string]: any; } type OptionsType<OptionType extends OptionTypeBase> = ReadonlyArray<Opt ...

Incorporating data retrieved through AJAX requests into a Python function

The Flask application described below continuously makes Ajax calls to a backend index function that queries a database and injects the results into a template. However, the injected data is not being refreshed after the Ajax calls are completed, leading ...

Configuring Proxy Settings for WebpackDevServer

I need assistance setting up a proxy using WebpackDevServer in my React/Node chrome extension. Currently, my server is running on localhost:4000, and the React frontend is on localhost:5000. When trying to access the route /api/user/ticket using Axios, I ...

Blackberry Browser's Window.Opener Feature

Does anyone else experience issues with the blackberry browser(5.0) and the javascript window.opener function? I couldn't find much help on Google regarding this problem. We have a pre-existing website that successfully populates parent window form f ...

Error in Angular: Detected a circular dependency with $cookies

Encountered this error message: "Error: [$injector:cdep] Circular dependency found: $cookies <- $cookies <- AuthService" While using the code below 'use strict'; angular. module('core.auth'). factory('AuthService' ...

Utilize mongoose-delete to bring back items that have been marked for deletion but are still

Whenever I remove an item from my list, it switches the properties of the data to true, marking it as deleted and moves it to the trash. However, when I try to restore the item from the trash, the deleted properties are no longer available and the data rea ...

Using Angular to pass an attribute into a directive and utilizing it as a property name on an object

Is it possible to utilize the checkType attribute in a way that resolves as scope.countFrom = sseHandler.broadcastStamp[checkType];? I am attempting to do this in order to easily input the value and create a reusable directive. Currently, I am encounterin ...

What methods can I employ to utilize preg_match with jQuery?

Is it possible to validate a phone number in jQuery using preg_match? I have tried the following code without success: if (!preg_match("/^[0-9]{3}-|\s[0-9]{3}-|\s[0-9]{4}$/", phone.val() )) { phone.addClass("needsfille ...