I created a multi-step form using Laravel Livewire, and I cannot figure out how to get Stripe Elements to render/initiate on the 3rd step of my form, or any step besides the 1st step.
I understand it's not working because the Stripe JS is not initiating when I reach step 3 due to no page reload. I just don't understand how to initiate the Stripe JS when I'm on step 3 without reloading the page.
Here is a live working example of the issue I'm having (You can mess with the code here): https://laravelplayground.com/#/snippets/2f89e808-d9e1-404a-bd65-3dad6168d26e
Any help or a point in the right direction would be extremely helpful.
Livewire Component Class:
use Livewire\Component;
class LivewireComponent extends Component
{
public $pet_name;
public $pet_type;
public $cardHolderName;
public $step;
private $stepActions = [
'submit1',
'submit2',
'submit3'
];
public function mount()
{
$this->step = 0;
}
public function decreaseStep() {
$this->step--;
}
public function submit() {
$action = $this->stepActions[$this->step];
$this->$action();
}
public function submit1() {
$this->validate([
'pet_name' => 'required|min:1',
]);
$this->step++;
}
public function submit2() {
$this->validate([
'pet_type' => 'required',
]);
$this->step++;
}
public function submit3() {
dd($this->pet_name, $this->pet_type);
}
public function render()
{
return view('livewire-component');
}
}
Livewire Component: (I striped all the classes out so it's more readable)
<div>
<form wire:submit.prevent="submit">
{{--STEP 1--}}
@if($step == 0)
<div>
<label for="pet_name">Pet Name</label>
<input id="pet_name" wire:model.lazy="pet_name">
</div>
{{--ADD STRIPE ELEMENTS WORKS HERE ON 1ST STEP BUT NOT ON 3rd STEP--}}
{{-- @include('stripe-card-component') --}}
{{--/ADD STRIPE ELEMENTS/--}}
</div>
@endif
{{--STEP 2--}}
@if($step == 1)
<div>
<label for="pet_type">Pet Type | Cat or Dog</label>
<input id="pet_type" wire:model.lazy="pet_type">
</div>
@endif
{{--STEP 3--}}
@if($step == 2)
<div>
<p>This is where my issue is. I cannot figure out how to get Stripe Elements to InitIate on Steps other than the first step.</p>
{{--ADD STRIPE ELEMENTS DOES NOT WORK HERE ON 3RD STEP--}}
@include('stripe-card-component')
{{--/ADD STRIPE ELEMENTS DOES NOT WORK HERE ON 3RD STEP/--}}
</div>
@endif
//Buttons For Previous and Next Go Here
</form>
</div>
Stripe-Card Blade Component:
<div>
<label for="cardHolderName">Name on the card</label>
<div>
<input wire:model.lazy="cardHolderName" type="text" id="card-holder-name"/>
</div>
<label for="card">Card Details</label>
<div>
<div wire:ignore id="card-element"/>
</div>
</div>
//Goes to the header
@push('stripe')
<script src="https://js.stripe.com/v3/"></script>
@endpush
//Goes before end body tag
@push('stripe-js')
<script>
const stripe = Stripe('pk_RXwtgk4Z5VR82S94vtwmam6P8qMXQ');
const elements = stripe.elements();
const cardElement = elements.create('card');
cardElement.mount('#card-element');
const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;
cardButton.addEventListener('click', async (e) => {
const {setupIntent, error} = await stripe.confirmCardSetup(
clientSecret, {
payment_method: {
card: cardElement,
billing_details: {name: cardHolderName.value}
}
}
);
if (error) {
let errorWrapper = document.getElementById('error-wrapper')
errorWrapper.textContent = error.error
console.info(error)
} else {
// console.info(setupIntent.payment_method)
@this.set('paymentMethod', setupIntent.payment_method)
@this.call('submit')
}
});
</script>
@endpush
You can dispatch a browser event from Livewire on your last step.
With JS you can catch this event and then execute your Stripe JS code.
This will make your Stripe JS code execute without reloading the page.