Getting a getter length is called on Null error when trying to access List on Firebase using flutter

Viewed 62

I am trying to retrieve and display a list of items on firebase, I have been able to access everything else on firebase apart from the list itself. I think the issue might be how I am going about retrieving the list because of the method in which it was saved. Here is the order model code

import 'package:butcherbox/models/productsModel.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:meta/meta.dart';

class Order {
  Order(
      {@required this.items,
      //this.theItems,
      this.location,
      this.orderId,
      this.time,
      @required this.price});

  final List<ProductsModel> items;
  final String location;
  final int orderId;
  final Timestamp time;
  final int price;

  factory Order.fromMap(Map<String, dynamic> data) {
    if (data == null) {
      return null;
    }
    final List<ProductsModel> items = data['items'];
    final String location = data['location'];
    final int price = data['price'];
    final int orderId = data['orderId'];
    final Timestamp time = data['time'];

    return Order(
      items: items,
      location: location,
      price: price,
      orderId: orderId,
      time: time,
    );
  }


  Map<String, dynamic> toMap() {
    return {
      'item': items.map((e) => e.toJson()).toList(),
      'location': location,
      'orderId': orderId,
      'time': time,
      'price': price
    };
  }
}

This is the code to display the data

import 'package:butcherbox/butch_widgets/order_list_tile.dart';
import 'package:butcherbox/models/ordersmodel.dart';
import 'package:butcherbox/services/database.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class Orders extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        backgroundColor: Colors.green[200],
        title: Text(
          'Orders',
          textAlign: TextAlign.center,
          style: TextStyle(color: Colors.green[900]),
        ),
      ),
      body: _buildContents(context),
    );
  }

  Widget _buildContents(BuildContext context) {
    final database = Provider.of<Database>(context, listen: false);
    return StreamBuilder<List<Order>>(
        stream: database.ordersStream(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            final orders = snapshot.data;
            // final children =
            // orders.map((order) => Text(order.location)).toList();
            final children =
                orders.map((order) => OrderListTile(order: order)).toList();
            return ListView(children: children);
          }
          if (snapshot.hasError) {
            return Center(child: Text('Some Error Occurred'));
          }
          return Center(child: CircularProgressIndicator());
        });
  }
}

This is the widget for the UI

import 'package:butcherbox/models/ordersmodel.dart';
import 'package:flutter/material.dart';

class OrderListTile extends StatelessWidget {
  final Order order;

  const OrderListTile({Key key, @required this.order}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return ListTile(
      title: Text(
        'Order No: ${order.orderId}',
        style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.bold,
            color: Colors.green[900]),
      ),
      trailing: Text(
        'Vendor: ${order.location}',
        style: TextStyle(fontSize: 16),
      ),
      subtitle: ListView.builder(
          itemCount: order.items.length, <-- This is where the error is
          shrinkWrap: true,
          itemBuilder: (context, i) {
            return Expanded(
              child: Column(
                children: [
                  Text('${order.items[i].name}'),
                  Text('${order.items[i].quantity.toString()}')
                ],
              ),
            );
          }),
      isThreeLine: true,
    );
  }
}

This is the database code

import 'package:butcherbox/models/ordersmodel.dart';
import 'package:butcherbox/services/api_path.dart';
import 'package:meta/meta.dart';
import 'package:butcherbox/services/firestore_service.dart';

abstract class Database {
  Future<void> createOrder(Order order);
  Stream<List<Order>> ordersStream();
}

String docFromId() => DateTime.now().toIso8601String();

class FireStoreDatabase implements Database {
  FireStoreDatabase({@required this.uid}) : assert(uid != null);
  final String uid;
  final _service = FireStoreService.instance;

  Future<void> createOrder(Order order) => _service.setData(
        //path: APIPath.order(uid, 'orderdetails'), data: order.toMap());
        path: APIPath.order(uid, docFromId()),
        data: order.toMap(),
      );

  Stream<List<Order>> ordersStream() => _service.collectionStream(
      path: APIPath.orders(uid), builder: (data) => Order.fromMap(data));
}
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';

class FireStoreService {
  FireStoreService._();
  static final instance = FireStoreService._();

  Future<void> setData({String path, Map<String, dynamic> data}) async {
    final reference = FirebaseFirestore.instance.doc(path);
    print('$path: $data');
    await reference.set(data);
  }

  Stream<List<T>> collectionStream<T>({
    @required String path,
    @required T Function(Map<String, dynamic> data) builder,
  }) {
    final reference = FirebaseFirestore.instance.collection(path);
    final snapshots = reference.snapshots();
    return snapshots.map((snapshot) => snapshot.docs
        .map(
          (snapshot) => builder(snapshot.data()),
        )
        .toList());
  }
}
1 Answers

Yes actually you are right, so here are some keypoints,

  Stream<List<Order>> ordersStream() => _service.collectionStream(
      path: APIPath.orders(uid), builder: (data) => 
// This is supposed to be a list of Orders.
Order.fromMap(data));

You can try printing the data here so you see what I am talking about(it would be a List and not a singular object).

Related