Angular 5(CLI)中如何将index.js的成功消息传递至TypeScript组件
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/catchblock to handle errors and setstatus: 'FAILED'with the error message - Used
async/awaitfor 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

