observeRealtimeDBValue<T> method

Future<ValueNotifier<T?>> observeRealtimeDBValue<T>(
  1. String path
)

/////////////// /////////////// Observes a specific field in a Firestore document in real-time.

  • documentPath: Path to the Firestore document.
  • fieldPath: Path to the nested field within the document (e.g., "data/lastUpdatedTime").

Returns a ValueNotifier that emits updates whenever the specified field changes.

Usage Example:

ValueNotifier<String?> notifier = rtdb.observeRealtimeDBValue<String>('users/user123', 'profile/name');
notifier.addListener(() {
  print('Name updated to: ${notifier.value}');
});

Implementation

// Real-Time Observation //
//////////////////

/// Observes a specific field in a Firestore document in real-time.
///
/// - [documentPath]: Path to the Firestore document.
/// - [fieldPath]: Path to the nested field within the document (e.g., "data/lastUpdatedTime").
///
/// Returns a [ValueNotifier] that emits updates whenever the specified field changes.
///
/// **Usage Example**:
/// ```dart
/// ValueNotifier<String?> notifier = rtdb.observeRealtimeDBValue<String>('users/user123', 'profile/name');
/// notifier.addListener(() {
///   print('Name updated to: ${notifier.value}');
/// });
/// ```
Future<ValueNotifier<T?>> observeRealtimeDBValue<T>(String path) async {
  if (_listenedValues.containsKey(path)) {
    return _listenedValues[path] as ValueNotifier<T?>;
  }

  final notifier = ValueNotifier<T?>(null);

  // Fetch initial data
  try {
    final initialData = await getData(path);
    if (initialData is T) {
      notifier.value = initialData;
    } else {
      notifier.value = null;
      if (debug) {
        debugPrint(
            'Type mismatch: Expected type $T, but got ${initialData.runtimeType} for path $path.');
      }
    }
  } catch (error) {
    debugPrint('Error fetching initial data for $path: $error');
  }

  // Set up real-time observation using streams
  final streamController = _observeData(path);
  streamController.stream.listen((data) {
    if (data is T && data != notifier.value) {
      notifier.value = data;
    } else if (data is! T) {
      debugPrint(
          'Type mismatch: Expected type $T, but got ${data.runtimeType} for path $path.');
      notifier.value = null;
    }
  }, onError: (error) {
    debugPrint('Error observing Realtime Database value at $path: $error');
    notifier.value = null;
  });

  // Clean up when there are no listeners
  notifier.addListener(() {
    if (!notifier.hasListeners) {
      streamController.close();
      if (debug) {
        debugPrint('Subscription canceled for $path');
      }
    }
  });

  _listenedValues[path] = notifier;
  return notifier;
}