F
Filament17mo ago
KarlisJ

Custom field interacts with JS

I want to add Braintree Payment field to my form.
var button = document.querySelector('#submit-button');

braintree.dropin.create({
authorization: 'CLIENT_AUTHORIZATION',
container: '#dropin-container'
}, function (createErr, instance) {
button.addEventListener('click', function () {
instance.requestPaymentMethod(function (requestPaymentMethodErr, payload) {
// Submit payload.nonce to your server
});
});
});
var button = document.querySelector('#submit-button');

braintree.dropin.create({
authorization: 'CLIENT_AUTHORIZATION',
container: '#dropin-container'
}, function (createErr, instance) {
button.addEventListener('click', function () {
instance.requestPaymentMethod(function (requestPaymentMethodErr, payload) {
// Submit payload.nonce to your server
});
});
});
This is their simplest example. What would be the "filament" way of adding payload.nonce to the form.
10 Replies
KarlisJ
KarlisJOP17mo ago
to clarify my question, I need custom field to: - execute JS call when submitting the form (I would call instance.requestPaymentMethod) - populate the value of field from JS (I would set payload.nonce as the value for the field) There wouldn't actually be a field, it's a drop-in so fields are in iFrame.
Patrick Boivin
Patrick Boivin17mo ago
Not sure if I'm getting the full picture... do you need to make a request to Braintree and get some kind of token inside of a Hidden field as part of the Filament form submission?
KarlisJ
KarlisJOP17mo ago
Yes. My question is regarding the async nature of JS here. The payment field is last in my form. When the user submits the form I need to call instance.requestPaymentMethod in JS, wait for the response, put that value in hidden field and only then send all fields for validation/saving to the server.
Patrick Boivin
Patrick Boivin17mo ago
Makes sense. I'm not sure what the best solution is but I'm thinking that you may need to break down the submit action. Maybe this can be done with a "fake" submit button: - First, validate the form (call $this->validate() in Livewire) - Then, send the request to Braintree and show some kind of loading indicator - When you get the response, fill your Hidden field with the Braintree token - Finally, call the real submit() action I've never really done anything like this in the context of Filament. I'll be watching for suggestions from others.
awcodes
awcodes17mo ago
Does the call to Braintree have to happen on the front end? Using a hidden field to pass a token to the backend could have security implications if it's an authorization token.
Patrick Boivin
Patrick Boivin17mo ago
Totally agree
KarlisJ
KarlisJOP17mo ago
Does the call to Braintree have to happen on the front end? Using a hidden field to pass a token to the backend could have security implications if it's an authorization token.
Yes, it's the tokenization call. All payment providers (Stripe, etc) fallows this flow. There's client and server key. Client key is passed to browser, Braintree JS api is used to send card data to their server and return a token representing the payment method (card in this case) . I have to pass that to the backend and then perform the actual charge using server key. If someone intercepts the token, it's useless without server key. Given I have full control here and I need it in only specific place, I won't try to make it completely "right" by creating custom field. I'm thinking of handling the form fields separately and having 2 methods handling the submission. So I would have something like
{{ $this->form }}
// hidden input for token
// container for Braintree to render their checkout
// JS to render Braintree checkout
// Button that isn't type=submit.
{{ $this->form }}
// hidden input for token
// container for Braintree to render their checkout
// JS to render Braintree checkout
// Button that isn't type=submit.
Then I could add some JS to the button to both tokenize the card and hit validate method for form. On successful tokenization I trigger submit method in backend which calls the validate again (to be sure) and combines the form state with my hidden field.
awcodes
awcodes17mo ago
Maybe just use js to listen for the submit event then run a async await to get the token and set the hidden value then continue the default form submission. As a user if I hit enter I expect the form to submit. So you’d need a type=submit. Just my opinion though.
KarlisJ
KarlisJOP17mo ago
Hm, that sounds exactly what I need. Could be my lack of experience with LW that I fail to understand the technical aspects of how to achieve this. If I look at the simple example in Filament docs
<form wire:submit.prevent="submit">
<form wire:submit.prevent="submit">
here the submit method in PHP will be executed. Now from your last message
use js to listen for the submit
I understand something like this
<form id="js-id" wire:submit.prevent="submit">
...
<script>
document.getElementById("js-id").on('submit', ...
<form id="js-id" wire:submit.prevent="submit">
...
<script>
document.getElementById("js-id").on('submit', ...
But now there is still that PHP method being called, isn't it? Should I remove submit from form definition?
<form id="js-id" wire:submit.prevent>
<form id="js-id" wire:submit.prevent>
does that work?
awcodes
awcodes17mo ago
Hard to explain, but you can use alpine to handle the submit click and since alpine has access to the livewire instance after you’ve done your stuff you can call the livewire submit from there.
Want results from more Discord servers?
Add your server