Search code examples
flutterdartdart-null-safety

Removing elements from a list where several nested values are null or empty in dart and flutter


I want to get my contacts from my phone and save them into firebase. The following code works if all I wanted to do is save the contact name, mainly because the name cannot be empty in the phone but a problem arises when the nested value contact.phones is null or empty (shown below as "//works if I remove this").

Currently, if the phone field is empty, it throws a "StateError (Bad state: No element)" error.

Also, note that contacts.phone (result.phones after the attempt to remove the elements) is a list so I need to grab the first one.

I have tried to remove those elements from the list but that also sufferers from the same problem, the code to remove the empty phone fields fails for the same reason on this line.

if (!["", null, false, 0].contains(contact.phones?.first))

What is the correct way to remove elements from a list where the nested element is null or empty?



import '../../backend/backend.dart';
import '../../flutter_flow/flutter_flow_theme.dart';
import '../../flutter_flow/flutter_flow_util.dart';
import 'index.dart'; // Imports other custom actions
import 'package:flutter/material.dart';

import 'package:contacts_service/contacts_service.dart';

Future syncContactstoFirebase(String? userID) async {
  List<Contact> contacts = await ContactsService.getContacts();
List result = [];


for (var contact in contacts) {
  if (!["", null, false, 0].contains(contact.phones?.first)) {
    result.add(contact);
  }
}
  final instance = FirebaseFirestore.instance;

  CollectionReference collection =
      instance.collection('users').doc(userID).collection('contacts');

  late Map<String, dynamic> data;
  if (result != null)
    data = {
      'contacts': contacts
          .map((k) => {
                'name ': k.displayName,
                  'phone': k.phones?.first.value //works if I remove this
                    .toString()
                    .replaceAll(new RegExp(r"\s\b|\b\s"), "")
                    .replaceAll(new RegExp(r'[^\w\s]+'), '')
              })
          .toList(),
    };

  return collection
      .doc()
      .set(data)
      .then((value) => print("Contacts Updated"))
      .catchError((error) => print("Failed to update Contacts: $error"));
}

EDIT: See note below.

Is there a way to handle more than one nested element so for instance the mapping code becomes:-

  if (result != null)
    data = {
      'contacts': contacts
          .map((k) => {
                'name ': k.displayName,
                  'phone': k.phones?.first.value, 
                  'email': k.email?.value ///////ADDED THIS////////
                    .toString()
                    .replaceAll(new RegExp(r"\s\b|\b\s"), "")
                    .replaceAll(new RegExp(r'[^\w\s]+'), '')
              })
          .toList(),
    };


Solution

  • So simple when I got the syntax right, particularly the use of ! and ? in null safety. An if clause, before it adds the element in the mapping, is what does the trick.

      if (contacts != null)
        data = {
          'contacts': contacts
              .map((k) => {
                     if (k.displayName!.isNotEmpty && k.displayName !=null) 'name': k.displayName,
                     if (k.emails!.isNotEmpty && k.emails != null) 'email': k.emails?.first.value,
                     if (k.phones!.isNotEmpty && k.phones != null) 'phone': k.phones?.first.value
                        .toString()
                        .replaceAll(new RegExp(r"\s\b|\b\s"), "")
                        .replaceAll(new RegExp(r'[^\w\s]+'), '')
                        .replaceAll(new RegExp(r'/^(?!\s*$).+/'), '')
                  })
              .toList(),
        };