I'm still in the process of learning dart/flutter. I'm experimenting with ListView/ListTile and specifically onTap() from ListTile.

I'm somewhat familiar with JS/Jquery and am having trouble understanding the differences in approach between JS and flutter.

Please try to ignore any semantic or technical errors in the code below. I'm more concerned with theory/approach than if this is a perfectly formatted and syntactically correct example.

In JS, it's common to do something like make an AJAX call to an API to get a list of items for sale from a database. Assume the API returned 4 fields (primary key ID, isAvailable, item name, and item price). You then process the list and create/insert DOM elements for display.

<div id="234" data-isavailable="y" class=".itemsForSale">TV: $800</div>
<div id="345" data-isavailable="y" class=".itemsForSale">Microwave: $200</div>
<div id="456" data-isavailable="n" class=".itemsForSale">Book: $30</div>
<div id="567" data-isavailable="y" class=".itemsForSale">Sofa: $450</div>

You can then set listeners arbitrarily. For instance, you could do...

$( ".itemsForSale" ).click(function() {
   // do something
});

The click handler gets applied in "real-time". The code executed is aware of what was clicked and can analyze/interact with that item in the list. So, you can do something like:

$( ".itemsForSale" ).click(function() {
    var isAvailable = $(this).attr('data-isavailable');
    if( isAvailable == 'n' )
      alert('sorry but that item is out of stock!');
    else
      addItemToCart( $(this).attr('id') );
});

The point being, that the click handler doesn't necessarily know or care about the underlying data of each item. It becomes "context" aware during runtime and then pulls the relevant values out of the UI/etc.

With flutter, I'm looking to recreate similar functionality using a ListView and ListTile. Specifically, ListTile's onTap(). I'm getting confused because it seems like everything is coded "ahead of time".

Here is a basic example (ignore for now I'm not displaying price/etc)...

import 'package:flutter/material.dart';

class SecondScreen extends StatelessWidget {

  var mapper = {
    '234': 'TV',
    '345': 'Microwave',
    '456': 'Book',
    '567': 'Sofa'
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("Second Screen"),
        ),
        body:
            ListView.builder(  
              padding: const EdgeInsets.all(8.0),
              itemCount: mapper.length,
              itemBuilder: (BuildContext context, int index) {
                return ListTile(
                  key: new Key(mapper.keys.elementAt(index).toString()),
                  title: Text('${mapper.values.elementAt(index)}'),
                  onTap: () {
                    print('you clicked: ' + mapper.keys.elementAt(index).toString() );
                    addToShoppingCart( mapper.keys.elementAt(index).toString() ); // this doesnt exist yet and is just an example
                  } 
                );
              }
            )
    );
  }

}

First of all, I'm not even sure I need to assign a custom key to each ListView item (based on the database's primary key), but that's irrelevant for now.

What I'm getting stuck on is that the onTap handler doesn't seem to have an equivalent of "$(this)". Does flutter give each ViewTile it's "own" copy of onTap() and that each relevant key info is "hardcoded" into each one (for each itemBuilder loop, the current value of mapper.keys.elementAt(index).toString() is substituted into onTap() )?

I'm probably not describing my confusion properly and I'm not even sure all of the issues I'm going to run into. I'm sure my way of doing this is very "old" and not aligned with react and other newer approaches/frameworks (combining data within the UI elements).

I'm just having trouble seeing how I'm going to be able to add more complex logic (like checking availability of what was clicked).

Does anyone have any references or explanations that help me bridge this gap? I don't even know how to describe the concept of $(this) and how I would search for it in comparison to flutter/etc. I just know that something feels very different.

Thanks!


Solution 1: Sukhi

I understand your confusion probably because I'd a similar question when I started with Flutter just a few months back. And here is what I think -

It doesn't really matter whether the ListTile item has it's own copy of onTap() or not. A. It does not have it's own copy. (Following code snippet will explain) and B. Every programming language / SDK / whatever has its own way of working. What you are trying to say, probably, is that you've a BMW. It has got certain type of breaks. And you are trying to make exact type of break in Audi. It may not be right to do it as the other systems related to the breaks may not work in the optimised way.

Now, look at the following code snippet :

@override
  Widget build(BuildContext context) {
    return ListView.separated(
      separatorBuilder: (context, index) => ListViewDivider(),
      itemCount: faceRecTransactions.length,
      itemBuilder: (BuildContext context, int index) {
        return FacerecTransactionListItem(facerecTransaction: faceRecTransactions[index], onTap:()=> _onTap(faceRecTransactions[index],context),);
      },
    );

  }

  void _onTap(FacerecTransaction facerecTransaction, BuildContext context) {
    print('Status : ${facerecTransaction.userId}');
    Navigator.push(context, MaterialPageRoute(builder: (context) => FacerecDetailPage(
      facerecTransaction: facerecTransaction,
      criminalList: this.criminalList,)));

  }

There's no copy of onTap for every list item. It just 'feels' as it has because we write onTap inside ListView. If you look at the example above, when the user taps on certain item, then the onTap receives the information. We don't create array of onTap as such.

Since, there's no copy of onTaps, it's not really ahead of time code. It's pretty much works like in Ajax where the onTap doesn't really care about the payload. It just does the action(s) specified.

Now, in the above example, the Detailed Page can check the availability of the particular item. And if the item is not available then either appropriate message can be shown. Depending on the requirement, we can either write this code within onTap or on the next page. In short, the onTap can handle the complex logic as you need.