Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ollie_123's avatar

Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')

Morning All

I'm trying to integrate a payment gateway into my Latavel Livewire app and i'm coming up against the error Uncaught TypeError: Cannot read properties of null (reading 'addEventListener').

My JS isnt that strong so was hoping one of you kind folks might be able to assist.

For reference my input fields are set as wire:ignore. Firstly, the proceed method is called in the component which generates a new token from the payment provider and passes this to the view via a dispatchBrowserEvent which works fine.

<div class="flex flex-wrap justify-between items-center">
    @if($proceed == false)
    <button wire:click="proceed" class="button button-brand text-sm w-full">Add Payment Method</button>
    @elseif($proceed == true)

        <div class="card-title-accent uppercase pb-1">Card Details</div>
        <input wire:ignore type="text" id="hf-name" class="custom-input my-1" placeholder="Joe Smith">
        <input wire:ignore type="number" id="hf-number" class="custom-input my-1" placeholder="0000 0000 0000 0000">
        <div class="w-1/2">
            <input wire:ignore type="number" id="hf-date" class="custom-input my-1" placeholder="00/00">
        </div>
        <div class="w-1/2">
            <input wire:ignore type="number" id="hf-cvv" class="custom-input my-1" placeholder="000">
        </div>
        <button wire:ignore id="pay-btn" class="button button-brand text-sm w-full my-1">Pay now</button>
    @endif
</div>

However as it goes to parse the JS i get the above typeError for this section

let hf;
const cardholderName = document.querySelector('#hf-name')
const cardNumber = document.querySelector('#hf-number')
const cardDate = document.querySelector('#hf-date')
const cardCvv = document.querySelector('#hf-cvv')
const payBtn = document.querySelector('#pay-btn')

 window.addEventListener('preparePayment', function()  {
.......
// Payment button submit
            // Payment button submit
payBtn.addEventListener('click', () => {
    startLoading()
    // submits card data to pay
    hf.submit({ paymentData: PAYMENT_DATA })
        .then((res) => {
            stopLoading()
            hf.clear() // Clears payment fields (Cardholder name, Credit card number, expiration date, cvv)
            showResult(true)
            console.log('res', res)
        })
        .catch((err) => {
            stopLoading()

            if (err.code === 'NOT_VALID_CARD_DATA') {
                showResult(false, err.message)                    
            } else {
                showResult(false, err.message)
                hf.clear()
            }
            console.log('err', err)
        })
    })

.....

Please can someone advise where i might be going wrong.

Thank you in advance.

0 likes
6 replies
Sinnbeck's avatar

Why not use getElementById? It's what it's for :)

const payBtn = document.getElementById('pay-btn')
ollie_123's avatar

Hey @sinnbeck,

Thanks for your response. I tried getElementById too but got the same error :(

Sinnbeck's avatar

@ollie_123 what do you get if you do a console.log on payBtn? Did you remember to remove #?

ollie_123's avatar

@sinnbeck, i don't know whether its a conflict with livewire maybe as the fields: placeholders aren't populating the inputs from the JS either even though i've set the inputs to wire:ignore.

Here's some more code for reference if it helps:-

// Changed pay now button from button to input also to see if that helped
<input wire:ignore id="pay-btn"  value="Pay Now">

let hf;
const cardholderName = document.getElementById('hf-name')
const cardNumber = document.getElementById('hf-number')
const cardDate = document.getElementById('hf-date')
const cardCvv = document.getElementById('hf-cvv')
const payBtn = document.getElementById('pay-btn')

window.addEventListener('preparePayment', function() 
{
    window.dnaPayments.hostedFields.create({
        accessToken: event.detail.accessToken,
        styles: 
        {
        },
        threeDSecure: {
            container: threeDSecureModalContent
        },
        fields: 
        {
            cardholderName: {
                container: cardholderName,
                placeholder: 'Cardholder name'
            },
            cardNumber: {
                container: cardNumber,
                placeholder: 'Card number'
            },
            expirationDate: {
                container: cardDate,
                placeholder: 'Expiry date'
            },
            cvv: {
                container: cardCvv,
                placeholder: 'CSC/CVV'
            }
        }
        }).then((res) => {
            hf = res

            hf.on('dna-payments-three-d-secure-show', () => {
                $threeDSecureModal.modal('show')
            })

            hf.on('dna-payments-three-d-secure-hide', () => {
                $threeDSecureModal.modal('hide')
            })
        }).catch((err) => {
    })
    console.log('payBtn =', payBtn)
    // Payment button submit
    payBtn.addEventListener('click', () => {
        
        startLoading()
        // submits card data to pay
        hf.submit({ paymentData: PAYMENT_DATA })
            .then((res) => {
                stopLoading()
                hf.clear()
                showResult(true)
                console.log('res', res)
            })
            .catch((err) => {
                stopLoading()

                if (err.code === 'NOT_VALID_CARD_DATA') {
                    showResult(false, err.message)                    
                } else {
                    showResult(false, err.message)
                    hf.clear()
                }
                console.log('err', err)
            })
        })

    // data
    hf.submit(
    {
            paymentData: 
            {
                currency: 'GBP',
                description: 'test transaction',
                paymentSettings: 
                {
                }, 
            customerDetails: 
            {
            },
        }
    })
    .then((res) => {
        hf.clear(),
        console.log(res),
        Livewire.emit('transactionSuccess',res)
    })
    .catch((err) => {
        if (err.code === 'INVALID_CARD_DATA') {
            // do something
        } else if (err.code === 'THREE_D_SECURE_ERROR') {
            // do something
        } else {
            // do something
        }
    })
    // Final Close
})  
ollie_123's avatar

Hey @sinnbeck, just wondering if you had any other thoughts on this one.

I wrote a quick if condition & its coming up as not seen each time.

var payBtn = document.getElementById("pay-btn");

    // ---------- BUTTON TEST -------------
    if(payBtn)
    {
        console.log('button seen')
    }
    else
    {
        console.log('button not seen')
    }

If it helps, the whole script is placed before the last div in the livewire view and have tried using @push('scripts') ... @endpush and without but no difference. :(

Thanks in advance.

Please or to participate in this conversation.