0

I am creating an e-commerce app where homepage is kind of page where all fields like categories and other info is given.

here is my flow of screens ... HomeScreen -> CategoryPage -> ProductByCategory -> ProductLandingPage

I am getting error. New to Coding and learning Providers for 1st time, Not able to resolve this issue.

Error: Could not find the correct Provider above this ProductLandingPage Widget

To fix, please:

  • Ensure the Provider is an ancestor to this ProductLandingPage Widget
  • Provide types to Provider
  • Provide types to Consumer
void main() {
  runApp(MaterialApp(
    home: MultiProvider(
      providers: [
        ChangeNotifierProvider.value(
          value: Cart(),
        )
      ],
      child: HomeScreen(),
    ),
    debugShowCheckedModeBanner: false,
  ));
}
class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {


    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.redAccent,
        title: Text('Factory2Homes'),
        actions: <Widget>[
          IconButton(icon: Icon(Icons.search), onPressed: () {}),
          Consumer<Cart>(
            builder: (_, cart, ch) => Badge(
              child: ch,
              value: cart.itemCount.toString(),
            ),
            child: IconButton(
              icon: Icon(
                Icons.shopping_cart,
              ),
              onPressed: () {
              },
            ),
          ),
        ],
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[


            Container(height: 500, child: CategoryPage()),
          ],
        ),
      ),
    );
  }
}
class CategoryPage extends StatefulWidget {
  @override
  _CategoryPageState createState() => _CategoryPageState();
}

class _CategoryPageState extends State<CategoryPage> {
  @override
  Widget build(BuildContext context) {



    return FutureBuilder<List<AllCategory>>(

      future: getCategoryList(http.Client()),
      builder: (context, snapshot) {
        if (snapshot.hasError) print(snapshot.error);
        return snapshot.hasData
            ? ListOfCategories(
                categories: snapshot.data,
              )
            : Center(
                child: CircularProgressIndicator(
                backgroundColor: Colors.red,
              ));
      },
    );
  }
}

class ListOfCategories extends StatelessWidget {
  final List<AllCategory> categories;
  ListOfCategories({this.categories});

  @override
  Widget build(BuildContext context) {



    return GridView.builder(
      physics: NeverScrollableScrollPhysics(),
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(

        crossAxisCount: 2,

      ),
      itemCount: categories.length,
      itemBuilder: (context, index) {



        return InkWell(
          onTap: (){
            Navigator.push(context, MaterialPageRoute(builder: (context) => ProductByCategory(category: categories[index],)));

          },

            child: Image.network(categories[index].categoryIcon));
      },
    );
  }
}
class ProductByCategory extends StatefulWidget {
  final AllCategory category;
  final CarouselSlider carouselslider;

  ProductByCategory({this.category, this.carouselslider});

  @override
  _ProductByCategoryState createState() => _ProductByCategoryState();
}

class _ProductByCategoryState extends State<ProductByCategory> {
  @override
  Widget build(BuildContext context) {



    return Scaffold(
      appBar: AppBar(
        actions: <Widget>[
          Consumer<Cart>(
            builder: (_, cart, ch) => Badge(
              child: ch,
              value: cart.itemCount.toString(),
            ),
            child: IconButton(
              icon: Icon(
                Icons.shopping_cart,
              ),
              onPressed: () {
              },
            ),
          ),
          IconButton(icon: Icon(Icons.search), onPressed: () {}),
        ],
      ),
      body: FutureBuilder<List<Product>>(
        future: getCategoryByProduct(http.Client(), widget.category.id),
        builder: (context, snapshot) {

          if (snapshot.hasError) print(snapshot.error);
          if (snapshot.hasData) {
            return ProductByCategoryScreen(
              product: snapshot.data,
            );
          } else {
            return Center(child: CircularProgressIndicator());
          }
        },
      ),
    );
  }
}

class ProductByCategoryScreen extends StatefulWidget {
  final List<Product> product;

  ProductByCategoryScreen({this.product});

  @override
  _ProductByCategoryScreenState createState() =>
      _ProductByCategoryScreenState();
}

class _ProductByCategoryScreenState extends State<ProductByCategoryScreen> {
  @override
  Widget build(BuildContext context) {



    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount: 2,
      ),
      itemCount: widget.product.length,
      itemBuilder: (context, index) {

        return InkWell(
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) =>
                          ProductLandingPage(widget.product[index])));
            },
            child:
                Card(child: Image.network(widget.product[index].productPhoto)));
      },
    );
  }
}
class ProductLandingPage extends StatefulWidget {
  final Product product;

  ProductLandingPage(this.product);

  @override
  _ProductLandingPageState createState() => _ProductLandingPageState();
}

class _ProductLandingPageState extends State<ProductLandingPage> {


  @override
  Widget build(BuildContext context) {
    final cart = Provider.of<Cart>(context, listen: false);


    return Scaffold(
        appBar: AppBar(
          actions: <Widget>[

          ],
        ),
        body: SingleChildScrollView(
          child: Column(
            children: <Widget>[
              Container(
                color: Colors.green,
                height: MediaQuery.of(context).size.height / 2,
                child: Padding(
                  padding: const EdgeInsets.only(top: 8.0),
                  child: Image.network(widget.product.productPhoto),
                ),
              ),
              Divider(
                thickness: 1,
              ),
              Container(
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Text(this.widget.product.productName),
                ),
              ),
              Divider(),
              Container(
                child: Row(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: <Widget>[
                    Column(
                      children: <Widget>[
                        Padding(
                          padding: const EdgeInsets.only(left: 10.0),
                          child: Text(
                            '₹' + '${this.widget.product.productSalePrice}',
                            style: TextStyle(
                                fontSize: 30, fontWeight: FontWeight.w500),
                          ),
                        ),
                      ],
                    ),
                    Padding(
                      padding: const EdgeInsets.only(left: 8.0),
                      child: Center(
                        child: Text(
                            'MRP:' + '${this.widget.product.productListPrice}'),
                      ),
                    ),
                  ],
                ),
              ),
              Divider(),
              Row(
                mainAxisAlignment: MainAxisAlignment.start,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.only(left: 10.0),
                    child: Text(
                      'Description',
                      style:
                          TextStyle(fontSize: 18, fontWeight: FontWeight.w500),
                    ),
                  ),
                ],
              ),
              Container(
                child: Padding(
                  padding: const EdgeInsets.all(10.0),
                  child: Text(this.widget.product.productDescription),
                ),
              ),
            ],
          ),
        ),
        bottomNavigationBar: Container(
          width: MediaQuery.of(context).size.width,
          height: 45.0,
          child: RaisedButton(
            onPressed: () {
           cart.addItem(
               '${widget.product.productId}',
               widget.product.productListPrice,
               widget.product.productName,
            );
            },
            color: Colors.redAccent,
            child: Center(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Icon(
                    Icons.card_travel,
                    color: Colors.white,
                  ),
                  SizedBox(
                    width: 4.0,
                  ),
                  Text(
                    "ADD TO CART",
                    style: TextStyle(color: Colors.white),
                  ),
                ],
              ),
            ),
          ),
        ));
  }
}
class CartItem {
  final String id;
  final String title;
  final int quantity;
  final int price;

  CartItem({
    this.id,
    this.title,
    this.quantity,
    this.price,
  });
}

class Cart with ChangeNotifier {
  Map<String, CartItem> _items;

  Map<String, CartItem> get items {
    return {..._items};
  }

  int get itemCount{
    return _items==null ?0 :_items.length;
  }

  void addItem(
    String productId,
    int productListPrice,
    String productName,
  ) {
    if (_items.containsKey(productId)) {
      _items.update(
          productId,
          (existingCartItem) => CartItem(
                id: existingCartItem.id,
                title: existingCartItem.title,
                price: existingCartItem.price,
                quantity: existingCartItem.quantity + 1,
              ));
    } else {
      _items.putIfAbsent(
          productId,
          () => CartItem(
                id: DateTime.now().toString(),
                title: productName,
                price: productListPrice,
                quantity: 1,
              ));
    }
  }
}
chetan suri
  • 351
  • 1
  • 6
  • 16

2 Answers2

1

The idea of Provider is to lift the state management above the widgets so different children can easily access its state. So it would be helpful if you moved the HTTP request from the widget tree (where it will be called every time the UI updates, so users use more bandwidth than needed) to a provider that is created above the tree. Therefore the state doesn't need to passed around from widget to widget.

Try watching this amazing talk from the flutter team to get a better understanding of how to use provider: https://youtu.be/d_m5csmrf7I

Bdw read this StackOverflow answer about why .value isn't what you desire: How to deal with unwanted widget build?

So you should make the app like this

void main() => runApp(MyApp());


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      create: (context) => Cart(),
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Factory2Homes',
        home: HomeScreen(),
      ),
    );
  }
}
Gabber235
  • 168
  • 2
  • 8
0

i got it working by changing main.dart code to below code:

void main() => runApp(MyApp());


class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider.value(value: Cart(),
      child:MaterialApp(
        debugShowCheckedModeBanner: false,
        title: 'Factory2Homes',
        home: HomeScreen(),
      ),);
  }
}
chetan suri
  • 351
  • 1
  • 6
  • 16