0

I have a streambuilder that streams data from education collection and display a listview consist of cards. I have added gesture detector with edit icon in trailing of listview.

This is my streambuilder:

StreamBuilder<
    List<MyEducation>>(
stream: readEducation(),
builder:
    ((context, snapshot) {
  if (snapshot.hasError) {
    return Text(
        'Something went wrong ${snapshot.error}');
  } else if (snapshot
      .hasData) {
    final educations =
        snapshot.data!;

    return ListView(
      scrollDirection:
          Axis.vertical,
      shrinkWrap: true,
      children: educations
          .map(
              buildEducation)
          .toList(),
    );
  } else {
    return Center(
      child:
          CircularProgressIndicator(),
    );
  }
},),
)//streambuilder

This is the stream of list and the ListTile

 Stream<List<MyEducation>> readEducation() => FirebaseFirestore.instance
      .collection('education')
      .snapshots()
      .map((snapshot) => snapshot.docs
          .map((doc) => MyEducation.fromJson(doc.data()))
          .toList());

  Widget buildEducation(MyEducation educationss) => ListTile(
        enabled: isEnabled,
        leading: CircleAvatar(
          child: Image.network(educationss.universityImage),
        ),
        title: Text(educationss.universityName),
        // The icon button which will notify list item to change
        trailing: GestureDetector(
          child: new Icon(
            Icons.edit,
            color: Colors.black,
          ),
          onTap: () {
            openDialog(); //the opendialog for form
            setState(() {
              isEnabled = !isEnabled;
            });
          }, //this is the button edit
        ),
      );

After the opendialog is opened, I display form any user insert the data again then run this.

This is just the CreateEducation method:

Future createEducationCollege() async {
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (context) => const Center(
        child: CircularProgressIndicator(),
      ),
    );

    try {
      String date1 = selectedMonthStart! + " " + selectedYearStart.toString();
      print(date1);
      // DateFormat datestart = DateFormat.yMMMM(date1);
      // print(datestart);
      String date2 = selectedMonthEnd! + " " + selectedYearEnd.toString();
      print(date2);
      // DateFormat dateend = DateFormat.yMMMM(date2);
      // print(dateend);
      print(FirebaseAuth.instance.currentUser?.uid);
      final docEducation =
          FirebaseFirestore.instance.collection("education").doc();
      final uid = FirebaseAuth.instance.currentUser!.uid;
      final userEducation = MyEducation(
        uid: uid,
        universityName: collegeAheadController.text,
        universityImage: imageuniversitycollege,
        major: SelectedMajor.toString(),
        degree: SelectedDegree.toString(),
        dateEnd: date1,
        dateStart: date2,
      );
      final json = userEducation.toJson();

      await docEducation.set(json);
    } on FirebaseException catch (e) {
      Utils.showSnackBar(e.message);
    }

    //Navigator.of(context) not workking!!
    navigatorKey.currentState!.popUntil((route) => route.isFirst); 
}

How to change this into update the selected item for the firestore database?

This is the display

Actually I have no experience in edit selected data. I have search about edit selected data but its usually about users collection. How can I make the system know which list to change? I'm thinking of compare using equal to in .where() and change .set to .update.

Jessen Jie
  • 167
  • 1
  • 12
  • I would propose you start with a proper state management. Your approach may be ok for some sandpit trials, however, if the college wants to use it you may have a look at BlocLibrary, Riverpod or what else is around. At least BlocLibrary has quite some example tutorials which might answer your question – w461 Dec 13 '22 at 09:17
  • Thankyou for replying this i appreciate it i will look after it later, for now i try the answers by @Vaidehi Jamankar first because its looks more simple and suitable for my situation. – Jessen Jie Dec 14 '22 at 06:02

1 Answers1

2

Streambuilder listens to events coming from the stream not from your variables.You can have your stream as a state variable and when you change your date change your stream and the data will be refreshed.Widget rebuilding is scheduled by each interaction, using State.setState, but is otherwise decoupled from the timing of the stream.The FlutterFire documentation includes an example on how to listen to Firestore for events that can be used to update the widget. The same documentation page has a guide on how to update a value in the Firestore document with the update method .

DatabaseReference databaseRef; 
// initState() databaseRef = _database.child(widget.latestPath); 
// build return StreamBuilder( stream: databaseRef.onValue, builder: (context, snapshot) { // Do something with the data }, );
// When u want to update new path setState(() { databaseRef = _database.child(widget.newPath);; 
});

While working with the pressed card and widgets you need to wrap your functions with setState. onPressed: () { setState(() { _visibleBehavior = true; }) } Also you can try and use the setState method and refactor your pressed card details from StatelessWidget to StatefullWidget.
You can check the following similar examples:

Vaidehi Jamankar
  • 1,232
  • 1
  • 2
  • 10
  • Thankyou for your reply i will try it :) , so i need to start stream directly from firestore and make my streambuilder like this, apply the update method then it will update based on the snapshot id? – Jessen Jie Dec 14 '22 at 06:17
  • yes, please try with the above recommendations suitable with your setup. – Vaidehi Jamankar Dec 14 '22 at 06:25