最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Stripe elements: how can I validate a card element is not blank client-side? - Stack Overflow

programmeradmin0浏览0评论

Stripe recommends using the change event for client side validation of the card element:

cardElement.on('change', function(event) {
  if (eventplete) {
    // enable payment button
  } else if (event.error) {
    // show validation to customer
  }
});

However this approach makes it impossible to determine a card element is invalid if the user never edits / changes it. I can always try to submit the payment with confirmCardPayment but that is inefficient—this validation should be possible client-side.

I can work around this by having the payment form default to an error state that is then resolved (or not) the first time the user changes the card. However this is not convenient as it would require me to internationalize the "Your card number is incomplete" error message in my application code versus relying on Stripe to this.

Ideally I would be able to either synchronously check the card element for an error or at least synchronously trigger the change event but neither of these seem possible.

Stripe recommends using the change event for client side validation of the card element:

cardElement.on('change', function(event) {
  if (event.complete) {
    // enable payment button
  } else if (event.error) {
    // show validation to customer
  }
});

However this approach makes it impossible to determine a card element is invalid if the user never edits / changes it. I can always try to submit the payment with confirmCardPayment but that is inefficient—this validation should be possible client-side.

I can work around this by having the payment form default to an error state that is then resolved (or not) the first time the user changes the card. However this is not convenient as it would require me to internationalize the "Your card number is incomplete" error message in my application code versus relying on Stripe to this.

Ideally I would be able to either synchronously check the card element for an error or at least synchronously trigger the change event but neither of these seem possible.

Share Improve this question asked Jan 23, 2021 at 17:56 Tom LehmanTom Lehman 89.2k72 gold badges205 silver badges279 bronze badges 2
  • 1 there is more events like 'ready' or 'click' , the stripe accepts it – Mohamed Ghoneim Commented Jan 23, 2021 at 18:18
  • @MohamedGhoneim click does not help because what if the user never clicks? ready would work but that event doesn't provide any error information. – Tom Lehman Commented Jan 23, 2021 at 19:17
Add a comment  | 

3 Answers 3

Reset to default 10

Stripe.js applies several classes to every Stripe Element's container based on the state of the Element:

  • StripeElement--complete
  • StripeElement--empty
  • StripeElement--focus
  • StripeElement--invalid
  • StripeElement--webkit-autofill (Chrome and Safari only)

You can read more about these classes, including how to customize them, in Stripe's documentation.

It sounds like checking for the StripeElement--empty class might suffice for your use case. You can do something like this:

const cardElementContainer = document.querySelector('#card-element');

let cardElementEmpty = cardElementContainer.classList.contains('StripeElement--empty');

// Do things based on cardElementEmpty being true or false

I've also been looking to validate my elements without payment intent. Looks like stripe has this for exactly that.

elements.submit()

Look it up here https://stripe.com/docs/js/elements/submit

You could also create a custom hook for this that will ensure the elements have been interacted with before enabling the submit button

import {
  useState
} from 'react';
import {
  StripeElementChangeEvent
} from '@stripe/stripe-js';

export type CardErrors = {
  cardNumber ? : string;
  cardExpiry ? : string;
  cardCcv ? : string;
};

export type CardTouched = {
  cardNumber ? : boolean;
  cardExpiry ? : boolean;
  cardCcv ? : boolean;
};

export const useCardElementWithValidation = () => {
  const [cardErrors, setCardErrors] = useState < CardErrors > ({
    cardNumber: '',
    cardExpiry: '',
    cardCcv: '',
  });

  const [cardTouched, setCardTouched] = useState < CardTouched > ({
    cardNumber: false,
    cardExpiry: false,
    cardCcv: false,
  });

  const getCardElementProps = < T extends StripeElementChangeEvent > (
    type: keyof CardErrors,
  ) => ({
    className: 'form-control',
    options: {
      placeholder: ''
    },
    onChange: ({
      error,
      empty
    }: T) => {
      if (error) {
        setCardErrors((prevValue) => ({
          ...prevValue,
          [type]: error.message,
        }));
      } else if (empty) {
        setCardErrors((prevValue) => ({
          ...prevValue,
          [type]: 'This field is required',
        }));
      } else {
        setCardErrors((prevValue) => ({
          ...prevValue,
          [type]: '',
        }));
      }
      setCardTouched((prevValue) => ({
        ...prevValue,
        [type]: true,
      }));
    },
  });

  return {
    cardErrors,
    getCardElementProps,
    hasCardErrors: Object.values(cardErrors).some((error) => error),
    isCardTouched: cardTouched.cardCcv && cardTouched.cardExpiry && cardTouched.cardNumber,
  };
};

And then use this in the Component like this

const {
  cardErrors,
  getCardElementProps,
  hasCardErrors,
  isCardTouched
} = useCardElementWithValidation();

...

<CardNumberElement { ...getCardElementProps<StripeCardNumberElementChangeEvent> (
    'cardNumber',
  )
}
options = {
  {
    showIcon: true,
    placeholder: ''
  }
}
/> 
{
  cardErrors.cardNumber && ( <Form.Control.Feedback type = 'invalid'> {
      cardErrors.cardNumber
    } </Form.Control.Feedback>
  )
}

...

<Button
label = 'SUBMIT'
disabled = {
  hasCardErrors || !isCardTouched
}
onClick = {
  () => handleSubmit()
}
/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>

发布评论

评论列表(0)

  1. 暂无评论