1

I have a list that contains several documentsnapshots. when I do a list.contains(documentsnapshot) it always returns false. example:

DocumentSnapshot a = document;
List<DocumentSnapshot> snapshots = []
snapshots.add(a);

snapshots.contains(a) // false

stripped down version of actual code

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

class AddUsersDialog extends StatefulWidget {

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

class _AddUsersDialogState extends State<AddUsersDialog> {

  List<DocumentSnapshot> selected = [];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      body: Container(
        child: Column(
          children: <Widget>[
            // row to display the selected users
            Row(
              children: List.generate(selected.length,
                (index) => InkWell(
                   onTap: () => setState(() => selected.removeAt(index)),
                   child: Text(selected[index]['name']),
                 );
              ),
            ),
            // list of all users
            StreamBuilder<QuerySnapshot>(
                stream: getUsers(),
                builder: (BuildContext context,
                    AsyncSnapshot<QuerySnapshot> snapshot) {
                  if (snapshot.hasData) {
                    List<DocumentSnapshot> users = snapshot.data.documents;
                    return Flexible(
                      child: ListView.builder(
                        itemCount: users.length,
                        itemBuilder: (BuildContext context, int index) {
                          return ListTile(
                            leading: Text(users[index]['name']),
                            onTap: () => setState(() {
                              if (selected.contains(users[index])) return;
                              selected.add(users[index]);
                            }),
                          );
                        },
                      ),
                    );
                  } 
                }
             ),
          ],
        ),
      ),
    );
  }
} 

I get the streambuilder data, it displays nicely, I can add documentSnapshots to the selected list, and I can remove them again. only when I check in the users list if the user is already in the selected list, it will always return false, even though when I print the list, and the user, I can see that it's in there.

Solution apparently directly comparing DocumentSnapshots is going to give issues as described in the comments of Morez' answer. I solved it by creating a custom contains function

bool contains(List<DocumentSnapshot> list, DocumentSnapshot item) {
    for (DocumentSnapshot i in list) {
      if (i.documentID == item.documentID) return true;
    }
    return false;
  }
cas
  • 757
  • 4
  • 19

1 Answers1

2

I just ran a similar code but it's working as expected. Make sure your document is not null because that might be the problem. But if you add the document successfully, You would get snapshots.contains(a) as true.

Updated answer

I think the problem is that you are comparing objects. When you run the if statement the second time, you compare two different objects with same details because every time you run the builder, You create a new object in memory. So that 2 different memory locations are being compared and the result is always false and therefore you always add the object to the list. You can use identical(this,other) or have a look at their hash codes to see they are different objects.

The solution is to check for something unique of the objects and compare them. You can check their id or their name and if they are different, The users are different and then you add it to your list.

You can also have a look at this.

Morez
  • 2,085
  • 2
  • 10
  • 33
  • well yeah but, 1. item not in the list 2. if statement returns false 3. add item to the list 4. press the item a second time 5. item is already added to the list so if statement returns true, so item doesn't get added a second time. – cas Mar 25 '20 at 12:30
  • I can print the list and see that every time I click an item it get's added to that list – cas Mar 25 '20 at 12:31
  • So when you print the list, You have 2 of the same objects? or you only have one at the end? – Morez Mar 25 '20 at 12:42
  • when I print the List I have two of the same object, even though I checked if the list contained that item before I added another one. – cas Mar 25 '20 at 12:45
  • I think the problem is that you are comparing objects. When you run the if statement the second time, you compare two different objects with same details because every time you run the builder, You create a new object in memory. So that 2 different memory locations are being compared and the result is always false and therefore you always add the object to the list. Have a look at https://stackoverflow.com/questions/16069106/how-to-compare-two-java-objects – Morez Mar 25 '20 at 12:50
  • You can see that the hash code of the objects in the list are different and therefore they are different objects. What you can do is to check something unique of each object. For example the id or name. If they are the same then there is an object with same details in the list .Please try that and let me know if that's the issue – Morez Mar 25 '20 at 12:53
  • Have a look at https://stackoverflow.com/questions/18428735/how-do-i-compare-two-objects-to-see-if-they-are-the-same-instance-in-dart – Morez Mar 25 '20 at 12:57
  • you're welcome. I update my answer. Please accept and upvote it :) – Morez Mar 25 '20 at 13:05