richnologies / ngx-stripe

Angular 6+ wrapper for StripeJS
MIT License
219 stars 77 forks source link

Unable to use confirmSetup function with a group of components #176

Closed robert197 closed 1 year ago

robert197 commented 2 years ago

I have the following scenario:

my template looks like this:

<ng-container *ngIf="elementsOptions?.clientSecret">
  <ngx-stripe-card-group [(elementsOptions)]="elementsOptions">
    <ion-card>
      <ion-card-header>
        <ion-label> Number: </ion-label>
      </ion-card-header>
      <ion-card-content>
        <ngx-stripe-card-number
          [options]="cardOptions"
        ></ngx-stripe-card-number>
        <ion-text color="danger" *ngIf="hasNumberError">
          <p class="error-message">{{ numberErrorMessage }}</p>
        </ion-text>
      </ion-card-content>
    </ion-card>

    <ion-card>
      <ion-card-header>
        <ion-label> Expiration date: </ion-label>
      </ion-card-header>
      <ion-card-content>
        <ngx-stripe-card-expiry
          [options]="cardOptions"
        ></ngx-stripe-card-expiry>
        <ion-text color="danger" *ngIf="hasExpiryError">
          <p class="error-message">{{ expiryErrorMessage }}</p>
        </ion-text>
      </ion-card-content>
    </ion-card>

    <ion-card>
      <ion-card-header>
        <ion-label> CVC: </ion-label>
      </ion-card-header>
      <ion-card-content>
        <ngx-stripe-card-cvc [options]="cardOptions"></ngx-stripe-card-cvc>
        <ion-text color="danger" *ngIf="hasCvcError">
          <p class="error-message">{{ cvcErrorMessage }}</p>
        </ion-text>
      </ion-card-content>
    </ion-card>
  </ngx-stripe-card-group>
</ng-container>

I am having the following viewChilds in order to make custom validation in the code.

  @ViewChild(StripeCardNumberComponent) number: StripeCardNumberComponent;
  @ViewChild(StripeCardExpiryComponent) expiry: StripeCardExpiryComponent;
  @ViewChild(StripeCardCvcComponent) cvc: StripeCardCvcComponent;

in the code I am creating first the following variables:

  public cardOptions: StripeCardExpiryElementOptions = {
    style: this.baseStyle,
  };

  public elementsOptions: StripeElementsOptions = {
    locale: 'de',
  };

and then I am getting the setupIntentClient secret which works fine:

async ngOnInit() {
    try {
      const cs = await this.paymentService.getSetupIntentClientSecret();
      this.elementsOptions.clientSecret = cs;
    } catch (_) {
      this.showInitCardFormError();
    }
  }

notice I am setting the clientSecret property on the elementsOptions object. This works fine and the property is set.

Then im trying to add a credit card:

private async addCreditCard() {
    this.isLoading = true;
    try {
      const { setupIntent, error } = await this.stripeService
        .confirmSetup({
          elements: this.number.elements,
          redirect: 'if_required',
        })
        .toPromise();
      console.log(setupIntent, error);
      if (error) {
        console.error(error);
        await this.showSubmitCardFormError();
      } else {
        console.log(setupIntent);
      }
    } catch (e) {
      console.error(e);
      await this.showSubmitCardFormError();
    } finally {
      this.isLoading = false;
    }
  }

If I log this.number.elements I can see that there are 3 elements registered insider the _elements property. which probably means that the 3 elements. Card, exiration data and CVC are mounted correctly.

The problem is! when i run this code of addCreditCard function. I am getting the following error!

IntegrationError: Invalid value for stripe.confirmSetup(): elements should have a mounted Payment Element. It looks like you have other Elements on the page. Refer to https://stripe.com/docs/js/setup_intents/payment_method to confirm a Setup Intent by payment method. at f (v3:1:79863) at m.betas (v3:1:80971) at h (v3:1:81504) at v3:1:295888 at e. (v3:1:296343) at e.confirmSetup (v3:1:124038) at b.project (main.js:1:1788269) at b._next (main.js:1:1435108) at b.next (main.js:1:1409689) at G._next (main.js:1:1424661)

When I use the same logic but instead of a group using the ngix-stipe-payment component. everything works fine.

richnologies commented 2 years ago

Hi @robert197,

Thanks for raising this question.

You've done a great job and I can see how the docs can be a bit confusing. So, basically, the ConfirmPayment and ConfirmSetup can only be used with the new Payment Element this is way this statement is true:

When I use the same logic but instead of a group using the ngx-stripe-payment component. everything works fine.

If you want to use the credit card element, not matter if with a group or just in one element, you need to use this other methods, for Card Payments and Card Setups

Beside the method names, the main difference is that instead of passing the whole elements object, we just need to pass the card element. You can use this.number.element instead of this.number.elements in this case.

If have any more questions, please do not hesitate to ask, happy to help

Regards

R

richnologies commented 1 year ago

I'm closing this due to inactivity