如何将Stripe信用卡字段与`button`的`ng-disabled`属性集成?

时间:2018-02-19 19:37:34

标签: angularjs stripe-payments

我的页面中有一个表单,包含AngularJS和Stripe JS。

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"> <script type="text/javascript">
    var app=    angular.module("app",[]);
    app.config(function($interpolateProvider){
        $interpolateProvider.startSymbol("[[[");
        $interpolateProvider.endSymbol("]]]");
    });

    app.controller("Ctrl",function(stripeService, $scope, $rootScope){
        $scope.name=            "World";
        $scope.stripeCompleted= false;
        stripeService.start();
        $rootScope.on("stripedone", function(e,stripeEvent){
            $scope.stripeCompleted= stripeEvent.complete;
            $scope.$apply();
        });
    });
    app.service("stripeService", function($window,$rootScope){
        function start(){
            var btn=    document.querySelectorAll("#test")[0];

            var displayError=   document.getElementById('card-errors');
            var stripe=         Stripe("{{ stripe_key }}");
            var elements=       stripe.elements();

            var style=  {
                base: {
                    fontSize: "1.1875rem",
                    fontSmoothing: "always",
                    fontWeight: "600"
                }
            };

            var card=   elements.create("card", {style:style});
            card.mount("#card-element");
            card.addEventListener('change', function(event) {
                if (event.error) {
                    displayError.textContent = event.error.message;
                } else {
                    displayError.textContent = '';
                }

                if (event.complete) {
                    $rootScope.$broadcast("stripedone",event);
                } else {
                    $rootScope.$broadcast("stripedone",event);
                }
            });

            var formID= "register-form";
            var form=   document.getElementById(formID);
            form.addEventListener("submit",function(event){
                event.preventDefault();                             
                stripe.createToken(card).then(function(result){
                    if(result.error) {
                        displayError.textContent=   result.error.message;
                    } else {
                        stripeTokenHandler(result.token, formID);
                    }                               
                });
            });

            return {"start":start};                             
        }
    });

    // tut https://stripe.com/docs/stripe-js/elements/quickstart#create-form
    function stripeTokenHandler(token, formID) {
        // Insert the token ID into the form so it gets submitted to the server
        var form = document.getElementById(formID);
        var hiddenInput = document.createElement('input');
        hiddenInput.setAttribute('type', 'hidden');
        hiddenInput.setAttribute('name', 'stripeToken');
        hiddenInput.setAttribute('value', token.id);
        form.appendChild(hiddenInput);
        // Submit the form
        form.submit();
    }
</script>    <form id="register-form" name="regForm" method="post>
    <input ng-model="reg.email" type="email" name="username">
    <div id="stripe-wrapper">
        <div id="card-element"></div>
    </div>
    <small id="card-errors" class="text-danger" role="alert">{{ ccErrMsg }}</small>
    <br>
    <button type="submit" ng-model="reg.btn" ng-disabled="!regForm.username.$valid>Register</button>
</form>

我希望我的button无法点击,除非用户正确填写了Stipe信用卡部分。除非条纹信用卡字段填写正确,否则如何禁用我的button

更新:按照karthick的回答给我一个新的错误:

angular.js:13642 TypeError: stripeService.start is not a function
    at Object.<anonymous> ((index):135)
    at Object.invoke (angular.js:4708)
    at P.instance (angular.js:10177)
    at n (angular.js:9096)
    at g (angular.js:8459)
    at angular.js:8339
    at angular.js:1782
    at m.$eval (angular.js:17378)
    at m.$apply (angular.js:17478)
    at angular.js:1780

1 个答案:

答案 0 :(得分:6)

在这种情况下,你应该使用AngularJS directive 。这不属于控制器,服务,工厂或组件。使用指令后,您的代码将变得更加智能,并得到AngularJS diggest循环和DOM绑定的完全支持。这是文档引入指令的方式:

  

什么是指令?在较高的层次上,指令是DOM元素上的标记(例如属性,元素名称,注释或CSS类),它们告诉AngularJS的HTML编译器($ compile)将指定的行为附加到该DOM元素(例如,通过事件侦听器),甚至转换DOM元素及其子元素。

<强>&GT; Demo fiddle

通过使用一个好的指令,你的解决方案可以像这样聪明:

视图

<body ng-app="angularjs-starter">
  <script src="https://js.stripe.com/v3/"></script>
  <div ng-controller="MainCtrl">
    <form name="regForm" id="register-form">
      <label>Mail</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>

AngularJS Application / Stripe.js卡验证指令

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

app.controller('MainCtrl', function($scope, $rootScope) {
  //Init stripe state via 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) {

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

      //mount 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 complete
        scope.stripeComplete = event.complete ? true : false;

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

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

        //prevent form submit
        event.preventDefault();

        //handle token, handle error and form submit forward
        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 submit
          form.submit();
        })
      });
    }
  }
});