0

I have the following standard JavaScript to mount my Stripe Element to my DOM:

export function MountStripeElement() {

    const stripe = Stripe("pk_test...");

    const options = {
        mode: 'subscription',
        amount: 1099,
        currency: 'usd',
        // Fully customizable with appearance API.
        appearance: {/*...*/ },
    };

    // Set up Stripe.js and Elements to use in checkout form
    const elements = stripe.elements(options);

    // Create and mount the Payment Element
    const paymentElement = elements.create('payment');
    paymentElement.mount('#payment-element');
}

Later on, I am calling my own submit method manually (I can't register an event listener and pass elements as part of the mount element method above for various reasons) I need access to the Stripe elements object that was available to me when I mounted/created the element.

export async function CreateStripeSubscription() {

    event.preventDefault();

    var submitBtn = document.getElementById('submit');
    var stripe = Stripe("pk_test...");

    const handleError = (error) => {
        const messageContainer = document.querySelector('#error-message');
        messageContainer.textContent = error.message;
        submitBtn.disabled = false;
    }

    // Disable form submission while loading
    submitBtn.disabled = true;

    const { error: submitError } = await elements.submit();

    if (submitError) {
        handleError(submitError);
        return;
    }

    var paymentElement = elements.getElement('payment');

    // Confirm the PaymentIntent using the details collected by the Payment Element
    const { error } = await stripe.confirmPayment({
        paymentElement,
        clientSecret,
        confirmParams: {
            return_url: 'https://www.google.co.uk/',
        },
    });

    if (error) {

        handleError(error);
    } else {

    }
}

However the above is failing on this line as elements is undefined:

var paymentElement = elements.getElement('payment');

The Stripe documentation seems to suggest I can just grab the previously created payment element here

My question is, how can i get a handle on 'elements' later on when im trying to submit my form to Stripe (which requires the payment element) given I cannot pass it as a parameter from the initial MountStripeElement at the start. Surely being able to grab your payment element later in a separate method should be possible?

JsonStatham
  • 9,770
  • 27
  • 100
  • 181
  • As far as I can see, `elements` _is_ `undefined` in `CreateStripeSubscription`. Or are you defining it, but didn't show that in your example? The `const elements =...` in the first function is locally scoped, so not available later... – Matt Morgan Jun 18 '23 at 21:53
  • This is my understanding too, but my question is how can i access the elements object again, later - the way i need to – JsonStatham Jun 19 '23 at 07:16
  • In the first method i am initializing the elements object with options, but in the second method, i just want to retrieve the already existed elements object without passing it options or re-creating it – JsonStatham Jun 19 '23 at 09:17
  • It seems like your issue doesn't really have anything specifically to do with Stripe, but it's an issue of variable scope. I suggest reading this question and its answers: https://stackoverflow.com/questions/500431/what-is-the-scope-of-variables-in-javascript – Matt Morgan Jun 19 '23 at 12:39
  • I suppose the question is how (using the Stripe.js library that is available to me across all my own methods) do i retrieve the previously created Stripe element. I can only see example of how to create it, but i want to retrieve it – JsonStatham Jun 19 '23 at 12:48

1 Answers1

0

The answer was to declare the variables globally outside the function using var, then assign values to them later on. I could then re-use these globally defined variables in my other function:

var stripe;
var elements;

export function MountStripeElement() {

    stripe = Stripe("pk_test...");

    ...    

    elements = stripe.elements(options);
  
    const paymentElement = elements.create('payment');
    paymentElement.mount('#payment-element');
}
JsonStatham
  • 9,770
  • 27
  • 100
  • 181
  • It doesn't need to be `var`. Modern best practice would be to use `let`. – Matt Morgan Jun 20 '23 at 13:04
  • For reference: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/First_steps/Variables#a_note_about_var – Matt Morgan Jun 20 '23 at 13:22
  • My understanding was that variables declared by let are only available inside the block in which they are defined and therefore would not work in my example? – JsonStatham Jun 21 '23 at 08:08
  • By declaring the variables at the top of the module, the _references_ are available everywhere in that module. That doesn't mean they've been _assigned_ yet, but since assigning it in the first function, then accessing it later is your exact use case, it will work. And you really should avoid using `var`, for reasons mentioned in the post I linked. – Matt Morgan Jun 21 '23 at 20:51
  • I will change it to let and check it still works as desired then update the answer, thanks Matt – JsonStatham Jun 23 '23 at 14:37