chetan suri
chetan suri

Reputation: 399

Flutter Error : Could not find the correct Provider<Cart> above this ProductLandingPage Widget

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:

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,
              ));
    }
  }
}

Upvotes: 0

Views: 735

Answers (2)

Gabber235
Gabber235

Reputation: 188

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(),
      ),
    );
  }
}

Upvotes: 1

chetan suri
chetan suri

Reputation: 399

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(),
      ),);
  }
}

Upvotes: 0

Related Questions