Search code examples
stripe-paymentsblazorblazor-client-sideblazor-webassembly

Adding Stripe Subscription to Blazor WASM


I am trying to add Stripe Subscription to my Blazor WASM Application following these instructions Since they are using JavaScript I am using the JavaScript interop. I added Stripe's script to my index.html and added a custom script with the javascript they have in the instructions. Index.html inside the <head> tag

<script src="https://js.stripe.com/v3/"></script>
<script src="stripescript.js"></script>

stripescript.js:

let stripe = window.Stripe('MY PUBLIC KEY');
let elements = stripe.elements();

let card = elements.create('card', { style: style });
card.mount('#card-element');

card.on('change', function (event) {
    displayError(event);
});
function displayError(event) {
    changeLoadingStatePrices(false);
    let displayError = document.getElementById('card-element-errors');
    if (event.error) {
        displayError.textContent = event.error.message;
    } else {
        displayError.textContent = '';
    }
}


function createPaymentMethod(cardElement, customerId, priceId) {
    return stripe
        .createPaymentMethod({
            type: 'card',
            card: cardElement,
        })
        .then((result) => {
            if (result.error) {
                displayError(error);
            } else {
                //change this to call .net
                createSubscription({
                    customerId: customerId,
                    paymentMethodId: result.paymentMethod.id,
                    priceId: priceId,
                });
            }
        });
}

My assumption is that the variable initializations would happen when the application is loaded. However, when I add the following HTML to my Razor page is not populating the card component.

<form id="payment-form">
    <div id="card-element">
        <!-- Elements will create input elements here -->
    </div>

    <!-- We'll put the error messages in this element -->
    <div id="card-element-errors" role="alert"></div>
    <button type="submit">Subscribe</button>
</form>

I am lost on how to debug this, or if this is even possible in Blazor.


Solution

  • Thanks to @Umair's Comments, I realized that I had made a few mistakes and some of them were showing up in the console since I was trying to initialize the card element before the DOM was loaded. I was able to fix my problem by first changing the card mount into its own function. Here is the full stripescript.js for future people that have this problem:

    let stripe = window.Stripe('MY KEY');
    let elements = stripe.elements();
    let style = {
        base: {
            fontSize: '16px',
            color: '#32325d',
            fontFamily:
                '-apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif',
            fontSmoothing: 'antialiased',
            '::placeholder': {
                color: '#a0aec0',
            },
        },
    };
    let card = elements.create('card', { style: style });
    
    function mountCard() {
        card.mount('#card-element');
    }
    
    card.on('change', function (event) {
        displayError(event);
    });
    function displayError(event) {
        changeLoadingStatePrices(false);
        let displayError = document.getElementById('card-element-errors');
        if (event.error) {
            displayError.textContent = event.error.message;
        } else {
            displayError.textContent = '';
        }
    }
    
    
    function createPaymentMethod(cardElement, customerId, priceId) {
        return stripe
            .createPaymentMethod({
                type: 'card',
                card: cardElement,
            })
            .then((result) => {
                if (result.error) {
                    displayError(error);
                } else {
                    //todo change this to call .net
                    createSubscription({
                        customerId: customerId,
                        paymentMethodId: result.paymentMethod.id,
                        priceId: priceId,
                    });
                }
            });
    }
    

    and added the following C# code to my Blazor component to render the card:

    [Inject] IJSRuntime js { get; set; }
        protected override async Task OnAfterRenderAsync(bool firstRender)
        {
            await js.InvokeVoidAsync("mountCard");
        }