You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular 5(CLI)中如何将index.js的成功消息传递至TypeScript组件

How to Pass Stripe Payment Success Message to Angular's make-payment.component.ts from Firebase Cloud Functions

Got it, let's walk through how to send that payment success notification from your Firebase Cloud Function over to your Angular component. We'll split this into two key parts: updating your cloud function to track the payment status, then setting up your Angular component to listen for that status change.

1. Update Your Firebase Cloud Function to Track Success Status

First, let's modify your existing stripeCharge function to explicitly set a status field in the database once the charge succeeds (or fails). This gives your Angular app a clear signal to listen for.

Here's the updated function with comments pointing out the changes:

const functions = require('firebase-functions')
const admin = require('firebase-admin')
admin.initializeApp(functions.config().firebase);
const stripe = require('stripe')(functions.config().stripe.testkey)

exports.stripeCharge = functions.database
  .ref('/payments/{userId}/{paymentId}')
  .onWrite(async (event) => { // Switch to async/await for cleaner code (optional but recommended)
    const payment = event.data.val();
    const userId = event.params.userId;
    const paymentId = event.params.paymentId;

    // Checks if payment exists or if it has already been charged
    if (!payment || payment.charge) return;

    try {
      // Fetch user data
      const userSnapshot = await admin.database().ref(`/users/${userId}`).once('value');
      const customer = userSnapshot.val();

      const amount = payment.amount;
      const idempotency_key = paymentId;
      const source = payment.token.id;
      const currency = 'usd';
      const charge = {amount, currency, source};

      // Create Stripe charge
      const stripeCharge = await stripe.charges.create(charge, { idempotency_key });

      // **Update: Add status field along with charge data**
      await admin.database()
        .ref(`/payments/${userId}/${paymentId}`)
        .set({
          ...payment, // Keep original payment data
          charge: stripeCharge,
          status: 'SUCCESS' // Mark payment as successful
        });

      return null;
    } catch (error) {
      // **Update: Handle failures by setting FAILED status**
      await admin.database()
        .ref(`/payments/${userId}/${paymentId}`)
        .set({
          ...payment,
          status: 'FAILED',
          error: error.message
        });
      // Re-throw the error to log it in Firebase Functions console
      throw error;
    }
  });

Key changes here:

  • Added status: 'SUCCESS' when the charge goes through
  • Added a try/catch block to handle errors and set status: 'FAILED' with the error message
  • Used async/await for more readable async code (you can stick with .then() if you prefer, but async/await is cleaner)

2. Listen for the Success Event in Your Angular Component

Now, in your make-payment.component.ts, you'll need to listen to the specific payment node in Firebase Realtime Database to detect when the status changes to SUCCESS. We'll use AngularFire (assuming you're using the AngularFire library for Firebase integration) to set up this listener.

Here's an example of how to implement this:

import { Component, OnDestroy } from '@angular/core';
import { AngularFireDatabase } from '@angular/fire/compat/database';
import { Subscription } from 'rxjs';
import { AngularFireAuth } from '@angular/fire/compat/auth';

@Component({
  selector: 'app-make-payment',
  templateUrl: './make-payment.component.html',
  styleUrls: ['./make-payment.component.css']
})
export class MakePaymentComponent implements OnDestroy {
  private paymentSubscription: Subscription | null = null;
  private userId: string | null = null;

  constructor(
    private db: AngularFireDatabase,
    private auth: AngularFireAuth
  ) {
    // Get current authenticated user ID
    this.auth.currentUser.subscribe(user => {
      this.userId = user?.uid || null;
    });
  }

  async makePayment(paymentData: any) {
    if (!this.userId) {
      console.error('User not authenticated');
      return;
    }

    // Step 1: Generate a unique payment ID
    const paymentRef = this.db.list(`/payments/${this.userId}`).push();
    const paymentId = paymentRef.key;

    if (!paymentId) {
      console.error('Failed to generate payment ID');
      return;
    }

    // Step 2: Write the payment data (including Stripe token) to the database
    await paymentRef.set({
      amount: paymentData.amount,
      token: paymentData.stripeToken,
      // Add any other payment details you need
    });

    // Step 3: Listen for the payment status update from the cloud function
    this.paymentSubscription = this.db.object(`/payments/${this.userId}/${paymentId}`)
      .valueChanges()
      .subscribe((payment: any) => {
        if (payment?.status === 'SUCCESS') {
          // **Trigger your success message here**
          alert('Payment successful!');
          // Update your UI: show success notification, reset form, etc.
          this.handlePaymentSuccess();

          // Unsubscribe to avoid memory leaks
          this.paymentSubscription?.unsubscribe();
        } else if (payment?.status === 'FAILED') {
          // Handle failure case
          alert(`Payment failed: ${payment.error}`);
          this.handlePaymentFailure(payment.error);
          this.paymentSubscription?.unsubscribe();
        }
      });
  }

  private handlePaymentSuccess() {
    // Add your success logic here: navigate to a confirmation page, update user data, etc.
  }

  private handlePaymentFailure(errorMessage: string) {
    // Add failure logic here: show error message, allow retry, etc.
  }

  ngOnDestroy() {
    // Clean up subscription when component is destroyed
    this.paymentSubscription?.unsubscribe();
  }
}

Important notes for this component:

  • We fetch the authenticated user ID via AngularFireAuth (no hardcoding needed)
  • We use valueChanges() to listen for real-time updates to the payment node
  • We unsubscribe from the subscription once we get a success/failure status to prevent memory leaks (also in ngOnDestroy)
  • Replace the alert() calls with your own UI components (like toast notifications) for a better user experience

Additional Tips

  • Security Rules: Make sure your Firebase Realtime Database security rules restrict access to /payments/{userId}/{paymentId} so users can only read/write their own payments. Example rule:
    {
      "rules": {
        "payments": {
          "$userId": {
            "$paymentId": {
              ".read": "$userId === auth.uid",
              ".write": "$userId === auth.uid"
            }
          }
        }
      }
    }
    
  • Loading State: Add a loading spinner while waiting for the payment status to update, so users know something is happening.
  • Error Handling: Add an error callback to the subscribe() method to handle cases where the listener might be disconnected.

内容的提问来源于stack exchange,提问作者ziggy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:42:06