UPDATE: It works if I wrap the form submission in a setTimeout(). Apparently it needs a little time for the updated values to "take". Now moving on to creating a standalone component instead.
Submitting a Stripe Checkout form with Vue, hidden elements are null
I'm attempting a pretty simple Stripe Checkout flow with Vue.
I have a form serving as the root element, with three buttons, each of which will select a particular subscription plan. Things seem to be working fine until the form is actually submitted. The hidden elements stripe_token and stripe_email come through with null values, even though they are being updated via v-model directives. In other words, if I stop short of submitting the form, they have values populated from the Stripe token, as evidenced by inspecting the DOM and by Vue Dev Tools. But once the form is submitted, those values seem to be wiped out.
The blade file:
@extends('layouts.master')
@section('content')
<div class="container">
{!! Form::open([
'url' => '/subscriptions',
'id' => 'checkoutForm',
]) !!}
@foreach ($plans as $plan)
<div>
{{ $plan->name }} {{ $plan->description }}
<button v-on:click.prevent="subscribe({{ $plan->id }})">Select</button>
</div>
@endforeach
<input type="hidden" name="selected_plan" v-model="selectedPlanId">
<input type="hidden" name="stripe_email" v-model="stripeEmail">
<input type="hidden" name="stripe_token" v-model="stripeToken">
{!! Form::close() !!}
</div>
@endsection
@push('scripts.body')
<script>
var plans = {!! $plans !!}; // JSON from the controller
</script>
<script src="https://checkout.stripe.com/checkout.js"></script>
<script src="/js/checkout.js"></script>
@endpush
checkout.js:
var vm = new Vue({
el: "#checkoutForm",
data: {
plans: plans, // From a global JSON array
selectedPlan: null, // Default value
stripeEmail: '', // v-model for hidden form field
stripeToken: '' // v-model for hidden form field
},
computed: {
selectedPlanId() {
if (this.selectedPlan) {
return this.selectedPlan.id;
}
return '';
}
},
methods: {
subscribe(planId) {
let plan = this.findPlanById(planId);
console.log(plan); // works
this.selectedPlan = plan;
// The following opens a Stripe checkout widget
// with all the correct information.
this.handler.open({
name: plan.name,
description: plan.description,
amount: plan.price * 100 // stored as decimal
});
},
findPlanById(id) {
return this.plans.find(plan => plan.id == id);
}
},
created() {
this.handler = StripeCheckout.configure({
key: window.Laravel.stripeKey,
locale: 'auto',
token: (token) => {
console.log(token); // works as expected
this.stripeToken = token.id; // Works in Vue Dev Tools
this.stripeEmail = token.email; // Works in Vue Dev Tools
// If we stop here, the hidden form elements are populated
// with the correct values.
this.$el.submit(); // Submits the form
// When the form hits the server, the hidden fields have null values???
}
});
}
})
And if I dd() the POST request:
array:4 [
"_token" => "fOz6VEqW2tNVMhAlB5s7XG6g9kfaBTqcnNIGkZYk"
"selected_plan" => "3"
"stripe_email" => null
"stripe_token" => null
]
It has to be something stupid I'm doing, but I'm not seeing it!
TIA
Please or to participate in this conversation.