Unbreachable
Unbreachable

Reputation: 744

Flutter, FieldValue.removeArray() is not working

I am trying to remove the elements from a list in the firestore db, but it's not working. What I find odd is that FieldValue.arrayUnion() and FieldValue.delete() works fine. Why is FieldValue.arrayRemove() the only one not working? Thanks.

Db service

 import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:firebase_auth/firebase_auth.dart';
    import "package:innovative_world/models/list_model.dart";

    class DatabaseService {
      // Collection Reference
      CollectionReference listCollection = Firestore.instance.collection("list");

      // Get current users id
      final String uid;
      DatabaseService({this.uid});

      // Set data to firestore db
      Future setUserData(List<String> list) async {
        return await listCollection.document(uid).setData({ 
          "list": list
        });
      }

      // DOES NOT WANT TO REMOVE ELEMENTS
      Future deleteListArr(int index) async {
        return await listCollection.document(uid)
          .updateData({ "list": FieldValue.arrayRemove([index]) });
      }

      // UserList snapshot
      UserList _userListFromSnapshot(DocumentSnapshot snapshot) {
        return UserList(
          uid: uid, 
          list: snapshot.data["list"].cast<String>().toList()
          ); 
      } 
      // Stream for user's to do list
      Stream<UserList> get userListStream {
        return listCollection.document(uid).snapshots()
          .map(_userListFromSnapshot);
      }
    }

Home

  import "package:flutter/material.dart";
    import 'package:flutter/rendering.dart';
    import "package:innovative_world/services/auth_service.dart";
    import "package:innovative_world/models/list_model.dart";
    import 'package:innovative_world/services/database_service.dart';
    import "package:innovative_world/shared/decoration.dart";
    import 'package:innovative_world/shared/loading.dart';
    import 'package:provider/provider.dart';
    import "package:innovative_world/models/user_model.dart";
    import "package:innovative_world/models/list_model.dart";


    class Home extends StatefulWidget {
      @override
      _HomeState createState() => _HomeState();
    }

    class _HomeState extends State<Home> {
      String _text;
      final _formKey = GlobalKey<FormState>();
      List<String> userDoc = [];


      @override
      Widget build(BuildContext context) {
        final user = Provider.of<UserId>(context);

        return StreamBuilder<UserList>(
            stream: DatabaseService(uid: user.uid).userListStream,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                UserList userList = snapshot.data;
                // List<String> userDoc = [userList.list.toString()];
                return Scaffold(
                  backgroundColor: Colors.blue[200],
                  appBar: AppBar(
                    title: Text(
                      "Create List",
                      style: TextStyle(
                        fontSize: 23.0,
                      ),
                    ),
                    elevation: 0.0,
                    actions: <Widget>[
                      FlatButton.icon(
                        onPressed: () {
                          AuthService().signOut();
                        },
                        icon: Icon(Icons.person),
                        label: Text("Sign out"),
                      ),
                    ],
                  ),
                  body: Padding(
                    padding: const EdgeInsets.fromLTRB(20.0, 25.0, 20.0, 0.0),
                    child: Column(
                      children: <Widget>[
                        Form(
                          key: _formKey,
                          child: Column(
                            children: <Widget>[
                              TextFormField(
                                validator: (val) =>
                                    val.isEmpty ? "Enter text" : null,
                                onChanged: (val) => setState(() => _text = val),
                                decoration: InputDecorationConst.copyWith(
                                    hintText: "Create List..."),
                              ),
                              RaisedButton(
                                onPressed: () async {
                                  if (_formKey.currentState.validate()) {
                                    userDoc.add(_text);

                                    _formKey.currentState.reset();
                                    await DatabaseService(uid: user.uid)
                                        .setUserData(userDoc ?? userList.list);
                                  }
                                },
                                color: Colors.pink,
                                child: Text(
                                  "Add to list",
                                  style: TextStyle(
                                      fontSize: 15.0, color: Colors.white),
                                ),
                              ),
                            ],
                          ),
                        ),
                        SizedBox(height: 15.0),
                        ListView.builder(
                          shrinkWrap: true,
                          itemCount: userList.list.length,
                          itemBuilder: (context, index) {
                            return ForList(index: index, theList: userList.list);
                          },
                        ),
                      ],
                    ),
                  ),
                );
              } else {
                return Loading();
              }
            });
      }
    }

    class ForList extends StatefulWidget {
      final int index;
      final List<String> theList;

      ForList({this.index, this.theList});

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

    class _ForListState extends State<ForList> {
      bool isSelected = false;

      @override
      Widget build(BuildContext context) {
        final user = Provider.of<UserId>(context);

        return Column(
          children: <Widget>[
            Card(
              child: CheckboxListTile(
                title: Text(widget.theList[widget.index]),
                value: isSelected,
                onChanged: (bool val)  {
                  setState(() {
                    isSelected = val;
                    if (isSelected) {
                    DatabaseService(uid: user.uid).deleteListArr(widget.index);
                    }
                  });
                },
              ),
            ),
          ],
        );
      }
    }

Right above is where I have a separate widget 'ForList' that holds the snapshot.data and the index, it all seems well to me, but I can't figure out why it won't remove the element from the db

Upvotes: 0

Views: 1012

Answers (1)

Unbreachable
Unbreachable

Reputation: 744

The reason arrayRemove() was not working was because it was needing more than just the index, but also the string to which it correlated to.

Db service

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import "package:innovative_world/models/list_model.dart";

class DatabaseService {
  // Collection Reference
  CollectionReference listCollection = Firestore.instance.collection("list");

  // Get current users id
  final String uid;
  DatabaseService({this.uid});

  // Set data to firestore db
  Future setUserData(List<String> list) async {
    return await listCollection.document(uid).setData({ 
      "list": list
    });
  }

  // For deleting the lists
  Future deleteListArr(String index) async {
    return await listCollection.document(uid)
      .updateData({ "list": FieldValue.arrayRemove([index]) });
  }
  


  // UserList snapshot
  UserList _userListFromSnapshot(DocumentSnapshot snapshot) {
    return UserList(
      uid: uid, 
      list: snapshot.data["list"].cast<String>().toList()
      ); 
  } 
  // Stream for user's to do list
  Stream<UserList> get userListStream {
    return listCollection.document(uid).snapshots()
      .map(_userListFromSnapshot);
  }
}

Home

import "package:flutter/material.dart";
import 'package:flutter/rendering.dart';
import "package:innovative_world/services/auth_service.dart";
import "package:innovative_world/models/list_model.dart";
import 'package:innovative_world/services/database_service.dart';
import "package:innovative_world/shared/decoration.dart";
import 'package:innovative_world/shared/loading.dart';
import 'package:provider/provider.dart';
import "package:innovative_world/models/user_model.dart";
import "package:innovative_world/models/list_model.dart";
import 'dart:async';

class Home extends StatefulWidget {
  @override
  _HomeState createState() => _HomeState();
}

class _HomeState extends State<Home> {
  String _text;
  final _formKey = GlobalKey<FormState>();
  List<String> userDoc = [];
  // On every refresh the userDoc starts from 0, so it overrides the data

  @override
  Widget build(BuildContext context) {
    final user = Provider.of<UserId>(context);

    return StreamBuilder<UserList>(
        stream: DatabaseService(uid: user.uid).userListStream,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            UserList userList = snapshot.data;
            // List<String> userDoc = [userList.list.toString()];
            return Scaffold(
              backgroundColor: Colors.blue[200],
              appBar: AppBar(
                title: Text(
                  "Create List",
                  style: TextStyle(
                    fontSize: 23.0,
                  ),
                ),
                elevation: 0.0,
                actions: <Widget>[
                  FlatButton.icon(
                    onPressed: () {
                      AuthService().signOut();
                    },
                    icon: Icon(Icons.person),
                    label: Text("Sign out"),
                  ),
                ],
              ),
              body: Padding(
                padding: const EdgeInsets.fromLTRB(20.0, 25.0, 20.0, 0.0),
                child: Column(
                  children: <Widget>[
                    Form(
                      key: _formKey,
                      child: Column(
                        children: <Widget>[
                          TextFormField(
                            validator: (val) =>
                                val.isEmpty ? "Enter text" : null,
                            onChanged: (val) => setState(() => _text = val),
                            decoration: InputDecorationConst.copyWith(
                                hintText: "Create List..."),
                          ),
                          RaisedButton(
                            onPressed: () async {
                              if (_formKey.currentState.validate()) {
                                userDoc.add(_text);
                                _formKey.currentState.reset();
                                await DatabaseService(uid: user.uid)
                                    .setUserData(userDoc ?? userList.list);
                              }
                            },
                            color: Colors.pink,
                            child: Text(
                              "Add to list",
                              style: TextStyle(
                                  fontSize: 15.0, color: Colors.white),
                            ),
                          ),
                        ],
                      ),
                    ),
                    SizedBox(height: 15.0),
                    ListView.builder(
                      shrinkWrap: true,
                      itemCount: userList.list.length,
                      itemBuilder: (context, index) {
                        return ForList(listsIndex: userList.list[index], index: index, theList: userList.list);
                      },
                    ),
                  ],
                ),
              ),
            );
          } else {
            return Loading();
          }
        });
  }
}

class ForList extends StatefulWidget {
  final int index;
  final String listsIndex;
  final List<String> theList;

  ForList({ this.listsIndex, this.index, this.theList });

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

class _ForListState extends State<ForList> {
  bool isSelected = false;

  @override
  Widget build(BuildContext context) {
    final user = Provider.of<UserId>(context);

    return Column(
      children: <Widget>[
        Card(
          child: CheckboxListTile(
            title: Text(widget.theList[widget.index]),
            value: isSelected,
            onChanged: (bool val) {
              setState(() {
                isSelected = val;
                Timer(Duration(seconds: 1), () {
                  setState(() async {
                  if (isSelected) {
                    await DatabaseService(uid: user.uid).deleteListArr(widget.listsIndex);
                   
                    }
                  });
                });
              });
            },
          ),
        ),
      ],
    );
  }
}

I now added a new argument in the 'ForList' instance, 'listsIndex", which contains the string alongside the index.

Upvotes: 1

Related Questions