kareniel / angularjs-stripe-elements

💳 Angular.js wrapper around Stripe Elements
Apache License 2.0
12 stars 6 forks source link

Cannot read property 'mount' of undefined #1

Closed AbdelMonnem closed 6 years ago

AbdelMonnem commented 6 years ago

Hi. I m using "angularjs-stripe-elements" with angularjs 1.6 and angular material. when i implenent the exact example you described in the readme file, I have this error: "TypeError: Cannot read property 'mount' of undefined at Object.link (index.js:37)" Any help?

kareniel commented 6 years ago

mount is a method on the Stripe element instance. The error suggests that the variable you are passing to as an element instance is undefined. Can I see your controller code?

AbdelMonnem commented 6 years ago

Sorry to be late @kareniel , I was trying other solutions ;) Of course, yes, here is my controller: 'use strict'; angular.module('REC95.paiement', ['ngRoute']) .controller('paiementCtrl', ['$scope', '$location', 'StripeElements', function($scope, $location, StripeElements) { var elements = StripeElements.elements() var element = elements.create('card', {}) element.on('change', handleChange) this.element = element function handleChange(e) { this.cardErrors = e.error ? e.error.message : '' } } ]);

kareniel commented 6 years ago

Thanks for the additional info @AbdelMonnem !

So, what's happening is that the code example in the readme is meant to go in a component controller, not a bare controller assigned to a route directly. The element object isn't instantiated when it's passed to .

Here's an example of a fully working app. Notice how the controller is assigned to a component.

I hope this helps!

<!DOCTYPE html>
<html>
<head>
  <title>angularjs-stripe-elements example</title>
</head>
<body>
  <h1>angularjs-stripe-elements example</h1>

  <payment-form></payment-form>

  <script src="https://js.stripe.com/v3"></script>
  <script src="bundle.js"></script>
</body>
</html>
var angular = require('angular')
require('angularjs-stripe-elements')

angular.module('example', [ 'angularjs-stripe-elements' ])
  .config(function (StripeElementsProvider) {
    StripeElementsProvider.setAPIKey(process.env.STRIPE_KEY)
  })
  .component('paymentForm', {
    controller: PaymentForm,
    template: `
      <form ng-submit="$ctrl.handleSubmit" method="post" id="payment-form">

        <stripe-element instance="$ctrl.element"></stripe-element>

        <div id="card-errors" role="alert">{{$ctrl.cardErrors}}</div>

        <button>Submit Payment</button>
      </form>`
  })

function PaymentForm (StripeElements) {
  var ctrl = this

  var elements = StripeElements.elements()
  var element = elements.create('card', {})

  element.on('change', handleChange)

  ctrl.element = element

  function handleChange (e) {
    ctrl.cardErrors = e.error ? e.error.message : ''
  }
}

var doc = angular.element(document)

doc.ready(() => angular.bootstrap(doc, ['example']))

ps: you can render a component on a route by declaring it in a template string:

  $routeProvider.when('/paiment', {
    template: '<payment-form></payment-form>'
  })
kareniel commented 6 years ago

I'm gonna close this as this seems resolved, but don't hesitate to open another issue if there's anything!

ronnievsmith commented 6 years ago

Stripe.js renders the inputs for credit card number, expiration, CVC in iFrames. You cannot create these or get at them with JavaScript. You can however style the containers as you want which will enable you to get pretty close matching to the UI of your website - Bootstrap, MDC-Web, or whatever.

If your elements are not displaying, try the below to get started.

<div class="stripe-custom-element">
    <label for="stripe-card">Card Number</label>
    <div class="" id="stripe-card"></div>
</div>
<div class="stripe-custom-element">
    <label for="stripe-exp">Expiration</label>
    <div class="" id="stripe-exp"></div>
</div>
<div class="stripe-custom-element">
    <label for="stripe-cvc">CVC</label>
    <div class="" id="stripe-cvc"></div>
</div>

var cardNumberElement = doc.getElementById("stripe-card");
var cardExpiryElement = doc.getElementById("stripe-exp");
var cardCvcElement = doc.getElementById("stripe-cvc");

var cardNumber = elements.create('cardNumber', {});
var cardExpiry = elements.create('cardExpiry', {});
var cardCvc = elements.create('cardCvc', {});

cardNumber.mount(cardNumberElement);
cardExpiry.mount(cardExpiryElement);
cardCvc.mount(cardCvcElement);        

registerElements([cardNumber, cardExpiry, cardCvc]);