Laravel Livewire 和 Cashier 双表单提交问题
Laravel Livewire and Cashier double form submit issue
我正在尝试让 Cashier 与 Livewire 一起工作,但我 运行 遇到了一个错误,我必须按两次提交按钮才能获得 paymentmethod
。
在此视频中:https://www.loom.com/share/cb27ce3ae8ab46fab27e68afc7900eb4
我正在尝试 dd();
以下内容。
dd($this->paymentmethod, $this->cardHolderName, $this->plan->title, $this->plan->stripe_id);
除了 $this->paymentmethod
之外,所有内容都在第一次提交时 return 编辑,我必须在 [=] 中第二次提交 $this->paymentmethod
到 return 的表格15=]
请注意,我不会在第二次提交表单时刷新页面。
相关代码如下:
Livewire 视图:
<div>
<h3 class="text-lg leading-6 font-medium text-gray-200">
Plan {{ $plan->title }} Checkout | ${{ $plan->priceFormat }}
</h3>
<form wire:submit.prevent="submitSubscription">
@if(Session::has('success'))
It submitted!
@endif
<div id="error-wrapper"></div>
<label for="cardHolderName">Name on the card</label>
<input wire:model.lazy="cardHolderName" type="text" id="card-holder-name"/>
@if(!$cardHolderName)
@error('cardHolderName')
<p>{{ $message}}</p>
@enderror
@endif
<label for="card" class="block text-sm font-medium leading-5 text-gray-200">Card Details</label>
<div wire:ignore id="card-element"/></div>
<button id="card-button" type="submit" wire:target="submitSubscription" data-secret="{{ $intent->client_secret }}">Submit</button>
</div>
@push('stripe')
<script src="https://js.stripe.com/v3/"></script>
@endpush
@section('in-page-scripts')
<script>
const stripe = Stripe('{{ config('cashier.key') }}');
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)
}
});
</script>
@endsection
Livewire 控制器:
<?php
namespace App\Http\Livewire\Subscription;
use App\Plan;
use Livewire\Component;
class PlansCheckout extends Component {
public $plan;
public $error;
public $cardHolderName;
public $paymentmethod;
public function mount(Plan $plan) {
$this->plan = $plan;
}
public function render() {
return view('livewire.subscription.plans-checkout', [
'intent' => auth()->user()->createSetupIntent(),
]);
}
public function submitSubscription() {
$data = $this->validate([
'cardHolderName' => 'required',
]);
dd($this->paymentmethod, $this->cardHolderName, $this->plan->title, $this->plan->stripe_id);
$this->reset();
}
}
任何有关如何解决此问题的帮助将不胜感激。
我认为你的流程是错误的。 $this->paymentmethod
将不会显示在您的 dd()
中,因为调用 submitSubscription
时条纹制作的 ajax 仍未完成(因此 @this.set
don尚未更改 public 变量 paymentmethod
,这仅在您第二次单击时发生)。
从按钮中删除 wire:target="submitSubscription"
并添加以下脚本而不是您的 @this.set()
@this.call('setPayment', setupIntent.payment_method)
}
});
所以在你的 livewire 组件中:
public function setPayment($paymentmethod){
$this->paymentmethod = $paymentmethod;
$this->submitSubscription();
}
此代码等待 stripe ajax 完成,在您的 livewire 组件中设置支付数据,然后提交订阅。
一旦成功返回令牌,最后使用@this.call('add_or_update_payment_method')
函数。
<div>
<h3 class="text-lg leading-6 font-medium text-gray-200">
Plan {{ $plan->title }} Checkout | ${{ $plan->priceFormat }}
</h3>
<form wire:submit.prevent="submitSubscription">
@if(Session::has('success'))
It submitted!
@endif
<div id="error-wrapper"></div>
<label for="cardHolderName">Name on the card</label>
<input wire:model.lazy="cardHolderName" type="text" id="card-holder-name"/>
@if(!$cardHolderName)
@error('cardHolderName')
<p>{{ $message}}</p>
@enderror
@endif
<label for="card" class="block text-sm font-medium leading-5 text-gray-200">Card Details</label>
<div wire:ignore id="card-element"/></div>
<button id="card-button" type="submit" wire:target="submitSubscription" data-secret="{{ $intent->client_secret }}">Submit</button>
</div>
@push('stripe')
<script src="https://js.stripe.com/v3/"></script>
@endpush
@section('in-page-scripts')
<script>
const stripe = Stripe('{{ config('cashier.key') }}');
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('add_or_update_payment_method')
}
});
</script>
@endsection
public $paymentmethod;
public function updatedPaymentmethod()
{
if (filled(auth()->user()->stripe_id)) {
$this->add_or_update_payment_method();
} else {
// notify user error
}
}
public function add_or_update_payment_method()
{
try {
if (!auth()->user()->hasPaymentMethod()) {
auth()->user()->createOrGetStripeCustomer();
auth()->user()->addPaymentMethod($this->paymentmethod);
auth()->user()->updateDefaultPaymentMethod($this->paymentmethod);
} else {
auth()->user()->updateDefaultPaymentMethod($this->paymentmethod);
}
return true;
} catch (\Exception $e) {
return false;
// error handling
}
}```
我正在尝试让 Cashier 与 Livewire 一起工作,但我 运行 遇到了一个错误,我必须按两次提交按钮才能获得 paymentmethod
。
在此视频中:https://www.loom.com/share/cb27ce3ae8ab46fab27e68afc7900eb4
我正在尝试 dd();
以下内容。
dd($this->paymentmethod, $this->cardHolderName, $this->plan->title, $this->plan->stripe_id);
除了 $this->paymentmethod
之外,所有内容都在第一次提交时 return 编辑,我必须在 [=] 中第二次提交 $this->paymentmethod
到 return 的表格15=]
请注意,我不会在第二次提交表单时刷新页面。
相关代码如下:
Livewire 视图:
<div>
<h3 class="text-lg leading-6 font-medium text-gray-200">
Plan {{ $plan->title }} Checkout | ${{ $plan->priceFormat }}
</h3>
<form wire:submit.prevent="submitSubscription">
@if(Session::has('success'))
It submitted!
@endif
<div id="error-wrapper"></div>
<label for="cardHolderName">Name on the card</label>
<input wire:model.lazy="cardHolderName" type="text" id="card-holder-name"/>
@if(!$cardHolderName)
@error('cardHolderName')
<p>{{ $message}}</p>
@enderror
@endif
<label for="card" class="block text-sm font-medium leading-5 text-gray-200">Card Details</label>
<div wire:ignore id="card-element"/></div>
<button id="card-button" type="submit" wire:target="submitSubscription" data-secret="{{ $intent->client_secret }}">Submit</button>
</div>
@push('stripe')
<script src="https://js.stripe.com/v3/"></script>
@endpush
@section('in-page-scripts')
<script>
const stripe = Stripe('{{ config('cashier.key') }}');
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)
}
});
</script>
@endsection
Livewire 控制器:
<?php
namespace App\Http\Livewire\Subscription;
use App\Plan;
use Livewire\Component;
class PlansCheckout extends Component {
public $plan;
public $error;
public $cardHolderName;
public $paymentmethod;
public function mount(Plan $plan) {
$this->plan = $plan;
}
public function render() {
return view('livewire.subscription.plans-checkout', [
'intent' => auth()->user()->createSetupIntent(),
]);
}
public function submitSubscription() {
$data = $this->validate([
'cardHolderName' => 'required',
]);
dd($this->paymentmethod, $this->cardHolderName, $this->plan->title, $this->plan->stripe_id);
$this->reset();
}
}
任何有关如何解决此问题的帮助将不胜感激。
我认为你的流程是错误的。 $this->paymentmethod
将不会显示在您的 dd()
中,因为调用 submitSubscription
时条纹制作的 ajax 仍未完成(因此 @this.set
don尚未更改 public 变量 paymentmethod
,这仅在您第二次单击时发生)。
从按钮中删除 wire:target="submitSubscription"
并添加以下脚本而不是您的 @this.set()
@this.call('setPayment', setupIntent.payment_method)
}
});
所以在你的 livewire 组件中:
public function setPayment($paymentmethod){
$this->paymentmethod = $paymentmethod;
$this->submitSubscription();
}
此代码等待 stripe ajax 完成,在您的 livewire 组件中设置支付数据,然后提交订阅。
一旦成功返回令牌,最后使用@this.call('add_or_update_payment_method')
函数。
<div>
<h3 class="text-lg leading-6 font-medium text-gray-200">
Plan {{ $plan->title }} Checkout | ${{ $plan->priceFormat }}
</h3>
<form wire:submit.prevent="submitSubscription">
@if(Session::has('success'))
It submitted!
@endif
<div id="error-wrapper"></div>
<label for="cardHolderName">Name on the card</label>
<input wire:model.lazy="cardHolderName" type="text" id="card-holder-name"/>
@if(!$cardHolderName)
@error('cardHolderName')
<p>{{ $message}}</p>
@enderror
@endif
<label for="card" class="block text-sm font-medium leading-5 text-gray-200">Card Details</label>
<div wire:ignore id="card-element"/></div>
<button id="card-button" type="submit" wire:target="submitSubscription" data-secret="{{ $intent->client_secret }}">Submit</button>
</div>
@push('stripe')
<script src="https://js.stripe.com/v3/"></script>
@endpush
@section('in-page-scripts')
<script>
const stripe = Stripe('{{ config('cashier.key') }}');
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('add_or_update_payment_method')
}
});
</script>
@endsection
public $paymentmethod;
public function updatedPaymentmethod()
{
if (filled(auth()->user()->stripe_id)) {
$this->add_or_update_payment_method();
} else {
// notify user error
}
}
public function add_or_update_payment_method()
{
try {
if (!auth()->user()->hasPaymentMethod()) {
auth()->user()->createOrGetStripeCustomer();
auth()->user()->addPaymentMethod($this->paymentmethod);
auth()->user()->updateDefaultPaymentMethod($this->paymentmethod);
} else {
auth()->user()->updateDefaultPaymentMethod($this->paymentmethod);
}
return true;
} catch (\Exception $e) {
return false;
// error handling
}
}```