Flutter list firstWhere method, E Com App 16

There are many useful methods in Dart which we use in Flutter. Especially when we build apps. One of such methods is firstWhere method.

In this section we will learn how and when we will use this dart list method in our on-going E Commerce app.

Firstly, we have been building this E Commerce app from scratch.

Why?

Because a beginner in Flutter may find it useful.

In addition she can understand each step.

For that reason we don’t want to miss any step. We’ve been explaining every small point that might be useful to understand the concepts.

The previous section has taught us how we can tap any product image and see the product detail.

Product detail - Smart Phone
Product detail – Smart Phone

But how did we do that?

To investigate the process from the beginning we will find that it starts from the entry point. 

How? We have initiated the process with the Change Notifier Provider whose “create” property returns the Products model class.

void main() {
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (_) => Products(),
        ),
        ChangeNotifierProvider(
          create: (context) => CartModel(),
        )
      ],
...
// code is incomplete for brevity
// visit GitHub repository for full code

In the Products model class we have instantiated a few Product objects with different properties.

And at the same time, we have defined a few methods so that child widgets in the E commerce app can listen to the change in state.

One of such methods is the “findById” method where we have passed the ID of products.

class Products with ChangeNotifier {
  final List<Product> _items = [
    Product(
      id: 'p1',
      title: 'Smart Phone',
      description: 'A Smart Phone - get big Discount!',
      price: 29.99,
      imageUrl:
          'https://cdn.pixabay.com/photo/2015/12/13/16/02/ios-1091302_960_720.jpg',
    ),
    Product(
      id: 'p2',
      title: 'Smart TV',
      description: 'A Smart TV.',
      price: 59.99,
      imageUrl:
          'https://cdn.pixabay.com/photo/2015/02/07/20/58/tv-627876_960_720.jpg',
    ),
...
Product(
      id: 'p5',
      title: 'Shirt',
      description: 'Designed with care.',
      price: 47.99,
      imageUrl:
          'https://cdn.pixabay.com/photo/2014/08/05/10/31/waiting-410328_960_720.jpg',
    ),
  ];
Product findById(String id) {
    return _items.firstWhere((prod) => prod.id == id);
  }
...
// code is incomplete for brevity
// visit GitHub repository for full code

If we take a close look at the above code, what do we see?

We find that the list of items uses a Dart list method “firstWhere” which passes an argument. 

But how we will use it in Flutter? Let’s dig a little bit deeper and find the reason.

Flutter list firstWhere

Although in reality this argument might be any data type, in this case, it is a product object.

Moreover, it returns and checks that the argument must be equal to the product ID.

A beginner may find this logic a little bit puzzling.

Why?

Because when and where will we use this method?

Next, we see the routes property of the Material App where we see the following line of code.

return MaterialApp(
      title: 'E Commerce App',
      debugShowCheckedModeBanner: false,
      theme: theme.light(settings.value.sourceColor),
      home: const ProductsOverviewScreen(),
      routes: {
        ProductDetailScreen.routeName: (ctx) => const ProductDetailScreen(),
        CartScreen.routeName: (ctx) => const CartScreen(),
      },
    );
...

It says one thing clearly. 

So far we have defined two routes. One of them is the Product detail screen.

Let’s see the product detail screen code.

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../models/products.dart';

class ProductDetailScreen extends StatelessWidget {
  static const routeName = '/product-detail';

  /// product detail page
  ///
  const ProductDetailScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final productId = ModalRoute.of(context)!.settings.arguments as String;
    final loadedProduct = Provider.of<Products>(
      context,
      listen: false,
    ).findById(productId);
print(productId);
    return Scaffold(
      appBar: AppBar(
        title: Text(loadedProduct.title),
      ),
      body: SingleChildScrollView(
        child: Column(
          children: <Widget>[
            SizedBox(
              height: 300,
              width: double.infinity,
              child: Image.network(
                loadedProduct.imageUrl,
                fit: BoxFit.cover,
              ),
            ),
            const SizedBox(height: 10),
            Text(
              '\$${loadedProduct.price}',
              style: const TextStyle(
                color: Colors.grey,
                fontSize: 20,
              ),
            ),
            const SizedBox(
              height: 10,
            ),
            Container(
              padding: const EdgeInsets.symmetric(horizontal: 10),
              width: double.infinity,
              child: Text(
                loadedProduct.description,
                textAlign: TextAlign.center,
                softWrap: true,
              ),
            )
          ],
        ),
      ),
    );
  }
}

Why have we used a print() method inside the build method?

Actually we want to see the product ID.

What do we see?

When we tap the first item, it prints out “p1”, and for the second item it prints out “p2”. And the process goes on like this.

How does it happen?

For that, we need to take a brief look at the Products model class again.

Products model class and ID of items

When we have instantiated the products objects so that we can display them on the home page, we passed a unique ID for each item.

class Products with ChangeNotifier {
  final List<Product> _items = [
    Product(
      id: 'p1',
      title: 'Smart Phone',
      description: 'A Smart Phone - get big Discount!',
      price: 29.99,
      imageUrl:
          'https://cdn.pixabay.com/photo/2015/12/13/16/02/ios-1091302_960_720.jpg',
    ),
    Product(
      id: 'p2',
      title: 'Smart TV',
      description: 'A Smart TV.',
      price: 59.99,
      imageUrl:
          'https://cdn.pixabay.com/photo/2015/02/07/20/58/tv-627876_960_720.jpg',
    ),
...

Next take a look at the product items controller. We have passed the unique ID as the argument.

Actually we have landed at the product detail screen from that controller. Right?

child: GestureDetector(
          onTap: () {
            Navigator.of(context).pushNamed(
              ProductDetailScreen.routeName,
              arguments: product.id,
            );
          },
          child: Image.network(
            product.imageUrl,
            fit: BoxFit.cover,
          ),
        ),
...
// see the full code of the product item controller at the GitHub Repository

Finally the cycle completes. 

As a result, we tap each product and see the product detail for that product only based on the unique ID. 

The ID passes as an argument, and finally we get that argument with a very special method as follows.

final productId =
        ModalRoute.of(context)!.settings.arguments as String; // is the id!

Therefore, there are a lot of things to cover. 

Otherwise we won’t understand how an E Commerce app builds up on its own.

In the coming sections, we will discuss these methods in great detail.

So stay tuned.

For this part, you can clone the respective GitHub Repository.

What Next?

Books at Leanpub

Books in Apress

My books at Amazon

GitHub repository

Python and Data Science

Twitter

Comments

Leave a Reply