elioav
elioav

Reputation: 61

FLUTTER: How to load data before build() method

Can you please help me? I need to load data from cloud firestore into a List<> and I need that before flutter runs the build() method. The idea is to have this list ready to use its values from a StreamBuilder. In the next image I explain what I want to solve:

VISUAL WIDGET: https://i.sstatic.net/fv0eg.jpg

Right now I request the Brands from Cloud Firestore using Futures, it works but I use an async method so when I have the List ready the Widget has rendered already and I can't search in List because is empty by the time StreamBuilder resolves. I know that I could request the data of a specific brand from the builder of the StreamBuilder BUT I think there's a better way to do it because the brand collecion won't change and I had to request the Brand Data in every StreamBuilder event, it could work but I don't feel so good about that solution. So if I could get a List at the beginig I can save many requests to get the brand data from cloud firestore.

CODE WIDGET:

class _GeneralInventoryPageState extends State<GeneralInventoryPage> {
  
  ServiceFirestore _serviceFirestore = new ServiceFirestore();
  static final _appResources = new AppResources(); 
  Stream<QuerySnapshot> _streamGenericProducts; // STREAM OF PRODUCTS OF CLOUD FIRESTORE
  List<MapMarca> _allBrands; // THIS IS THE LIST I WANT TO FILL WITH BRANDS OF CLOUD FIRESTORE
  
  @override
  void initState() { 
    super.initState();
    final productCollectionName = _appResources.getResource("productCollectionName");
    _streamGenericProducts = _serviceFirestore.serviceGetCollection(productCollectionName); // initialize Stream
    _allBrands = new List<MapMarca>(); //initialize List<brand>
    _getAllBrands();
  }
  
 void _getAllBrands() async {
    var marcasRaw = await _serviceFirestore.serviceGetUniqueDocumentByCollectionName(collectionName, documentId);
    if(marcasRaw == null){
      print("Error");
    }
    else{
      ModelMarca marcas  = ModelMarca.fromMap(Map<String, dynamic>.from(marcasRaw)); //decoding brands
      this._allBrands = marcas.listBrand; // set the List<brand>
    }
  }

  @override
  Widget build(BuildContext context) {
    
    return Scaffold(
      appBar: AppBar(
        title: Text('Inventario')
      ),
      body: Container(
        child: StreamBuilder(
          stream: this._streamGenericProducts,
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (!snapshot.hasData) {
              return CircularProgressIndicator();
            }
            else {
              List<ModelProduct> genericProductList = [];
              QuerySnapshot  querySnapshot = snapshot.data;
              querySnapshot.documents.forEach((doc){
                final genericProduct = ModelProduct.fromMap(Map<String,dynamic>.from(doc.data));
                genericProduct.strIdRecord = doc.documentID;
                genericProductList.add(genericProduct);
              });
              return createProductListView(context, genericProductList);
            }
            
          },
          )
        ),  
    );
  }
 
  //I use createProductListView to Create every product section detail (this method is not important)
  Widget createProductListView(BuildContext context, List<ModelProduct> genericProductList) {
    return ListView(
      children: List<Widget>.from(genericProductList.map((genericProducto)=>createProductListTile(context,genericProducto)).toList())
    );
  }
   
  // Here I build every single Product Detail, I simplify the code, please look how I get the Brand Name
  Widget createProductListTile(BuildContext context, ModelProduct genericProduct) {
    return Column(
      children: <Widget>[
        ListTile(
          title: Column(
            children: <Widget>[
              Row(
                children: <Widget>[
                  Container(
                    //code for getting the product image
                ),
                ]
              ),
              // some code about product info....
              Row(
                children: <Widget>[
                  Expanded(child: Text("Marca: ${_getBrandName(brandCode: genericProduct.strProductBrand)}")) //HERE I ALWAYS GET "NO BRAND INFO "
                ],
              ),
              // some code about product info...
            ],
          ),
        ),
      ],
    );
  }

  String _getBrandName({String brandCode}) {
    MapMarca marca = _searchBrand(brandId: brandCode);
    if(marca == null) {
      return "NO BRAND INFO"; // this is what is get when I run my app in the Brand Field
    }
    else {
      return marca.valor;
    }
  }
}

Upvotes: 3

Views: 6010

Answers (2)

Parth Pitroda
Parth Pitroda

Reputation: 997

try to load your data in didchangeDependenices:-

 @override
 void didChangeDependencies() {
  super.didChangeDependencies();
 
 //try to load all your data in this method :)

 }

Upvotes: 0

Aman kumar
Aman kumar

Reputation: 399

Try using a FutureBuilder

FutureBuilder(
    future: *Your Data to Load*,
    builder: (BuildContext context, AsyncSnapshot snapshot) {
      return *Your Widgets*;
 })

Upvotes: 4

Related Questions