Card.attach is not a function

Hello,

Im getting the error in the function initializeCard attaching the div to the card:

Initializing Card failed TypeError: card.attach is not a function

appId  = null;
locationId  = null;
form  = null;


function initializeCard(payments) {
    const card = payments.card();

    card.attach('#card-container');

    return card;
}

function fillPaymentForm(anAppId, aLocationId) {
    this.appId = anAppId;
    this.locationId = aLocationId;

    this.form = document.getElementById('payment-form');

    if (!window.Square) {
        throw new Error('Square.js failed to load properly');
    }

    const payments = window.Square.payments(this.appId, this.locationId);
    
    let card;

    try {
        card = initializeCard(payments);
    } catch (e) {
        console.error('Initializing Card failed', e);
        return;
    }

    const cardButton = form.getElementById('card-button');

    cardButton.addEventListener('click', function (event) {
        handlePaymentMethodSubmission(event, card);
    });
}

function handlePaymentMethodSubmission(event, paymentMethod) {
    event.preventDefault();

    try {
        // disable the submit button as we await tokenization and make a
        // payment request.
        cardButton.disabled = true;
        const token = tokenize(paymentMethod);
        const paymentResults = createPayment(token);
        displayPaymentResults('SUCCESS');

        console.debug('Payment Success', paymentResults);
    } catch (e) {
        cardButton.disabled = false;
        displayPaymentResults('FAILURE');
        console.error(e.message);
    }
}



// Call this function to send a payment token, buyer name, and other details
// to the project server code so that a payment can be created with
// Payments API
function createPayment(token) {
    const body = JSON.stringify({
        locationId,
        sourceId: token,
        idempotencyKey
    });

    console.log(body);

    const paymentResponse = fetch('/payment', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body,
    });
    if (paymentResponse.ok) {
        return paymentResponse.json();
    }
    const errorBody = paymentResponse.text();
    throw new Error(errorBody);
}

// This function tokenizes a payment method.
// The ‘error’ thrown from this async function denotes a failed tokenization,
// which is due to buyer error (such as an expired card). It's up to the
// developer to handle the error and provide the buyer the chance to fix
// their mistakes.
function tokenize(paymentMethod) {
    const tokenResult = paymentMethod.tokenize();
    if (tokenResult.status === 'OK') {
        return tokenResult.token;
    } else {
        let errorMessage = `Tokenization failed-status: ${tokenResult.status}`;
        if (tokenResult.errors) {
            errorMessage += ` and errors: ${JSON.stringify(
                tokenResult.errors
            )}`;
        }
        throw new Error(errorMessage);
    }
}

// Helper method for displaying the Payment Status on the screen.
// status is either SUCCESS or FAILURE;
function displayPaymentResults(aStatus) {
    const statusContainer = this.form.getElementById(
        'payment-status-container'
    );

    if (aStatus === 'SUCCESS') {
        statusContainer.classList.remove('is-failure');
        statusContainer.classList.add('is-success');
    } else {
        statusContainer.classList.remove('is-success');
        statusContainer.classList.add('is-failure');
    }

    statusContainer.style.visibility = 'visible';
}

It looks like there are a few issues with whats provided.

  1. Variable Scoping: Inside the fillPaymentForm function, you are trying to access appId, locationId, and form as if they were global variables, but you’ve declared them at the top as global variables. You should use this to refer to the properties of the current object (which in this case is this inside fillPaymentForm).To fix this, you can change instances of:
this.appId = anAppId;
this.locationId = aLocationId;
this.form = document.getElementById('payment-form');

to:

appId = anAppId;
locationId = aLocationId;
form = document.getElementById('payment-form');
  1. Undefined idempotencyKey: In the createPayment function, you reference the idempotencyKey variable, but it is not defined anywhere in the provided code. You should define it or pass it as a parameter to the function.For example:
function createPayment(token, idempotencyKey) {
    // Rest of the code
}
  1. form is not defined: In the displayPaymentResults function, you’re trying to access the form variable, but it’s not in the function’s scope. You should pass form as a parameter to this function.For example:
function displayPaymentResults(aStatus, form) {
    // Rest of the code
}
  1. cardButton is not defined in handlePaymentMethodSubmission: You’re trying to access cardButton inside the handlePaymentMethodSubmission function, but it’s not defined in the function’s scope. You should define it or pass it as a parameter to the function.For example:
function handlePaymentMethodSubmission(event, paymentMethod, cardButton) {
    // Rest of the code
}
  1. Variable Naming: You define card inside the fillPaymentForm function, but you reference it as paymentMethod inside the handlePaymentMethodSubmission function. You should use consistent variable names for clarity.
  2. Missing import: You’re using Square.js, but there is no import statement for it in the provided code. You’ll want to make sure you have imported Square.js properly before using it. :slight_smile: