본문 바로가기

플러터와 파이어베이스 4탄 - 파이어스토어에 데이터 수정하기(UPDATE), 데이터 삭제하기(Delete)

ironwhale 2022. 6. 19.

Flutter & FireBase(FireStore) 데이터 수정하기, 삭제하기 편

대망에 파이어스토어 CRUD편의 마지막입니다. 저장하기, 읽어오기, 수정하기, 삭제하기가 데이터베이스를 처음 접했을때 지겹게 듣고 실습했던 내용인데 이렇게 다시한면 파이어스토어에 CRUD를 복습해보는 경험을 했습니다. 

아마도몸이 익을때 까지 한 백번은 실습을 해야할텐데 그때마다 처음 시작하는 마음으로 자료를 찾아보는것이 어렵기 때문에 이렇게 시리즈로 한번 만들어 보았습니다. 


우선 가장 쉬운 삭제하기

DocumentReference에 delete() 메소드를 사용하면 간단하게 삭제 기능을 구현할수 있습니다. 

//DELETE
Future<void> deleteMemo(DocumentReference reference) async {
  await reference.delete();
}

삭제버튼은 아래와 코드와 같이 구현 하면 됩니다.data.reference는 데이터의 위치를 의미하는 DocumentReference를 의미합니다. 여기서 data는 FireModel data = datas[index]을 뜻합니다. 전체코드로 아래 있으니 참조하시기 바랍니다.   자세한 FireModel은 여기링크를 클릭해서 봐주세요.

IconButton(
  icon: const Icon(Icons.delete),
  onPressed: () {
    logger.d(data.reference);
    FireService().deleteMemo(data.reference!);
    setState(() {});
  },
)

데이터 수정하기(UPDATE)

수정하기 위한 메소드입니다. 특정 데이터를 골라서 수정해야 하기때문에 DocumentReference와 수정된 데이터가 Map 형태로 입력되서 DocumentReference의 set 메소드를 이용하여 수정하게 됩니다. 

 

수정하는 메소드

//UPDATE
Future updateMemo(
    {required DocumentReference reference, required Map<String, dynamic> json}) async{
  await reference.set(json);
}

 

수정하는 화면으로 가는 부분

간단하게 Navigator를 이용해서 수정하는 페이지로 가는 부분입니다. 수정하는 페이지로 갈때 FireModel data를 보내주고 수정하기 버튼을 누르면 value와 함께 이화면으로 돌아옵니다. value가 참이면 setState 함수를 이용해 새로고침해줍니다. 

onLongPress: () {
  Navigator.of(context).push(MaterialPageRoute(builder: (_){
    return EditScreen(fireModel: data);
  })).then((value){
    if(value){
      setState(() {});
    }
  });
}

수정하는 부분

수정할 부분의 FireModel을 받아와서 텍스트콘트롤러에 기본값으로 이전의 값은 넣어 줍니다. 

class EditScreen extends StatelessWidget {
  final FireModel fireModel;

  EditScreen({Key? key, required this.fireModel}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    TextEditingController controller =
        TextEditingController(text: "${fireModel.motto}");

//// 중략 /////

onPressed: () {
  FireModel updateModel =
      FireModel(motto: controller.text, date: Timestamp.now());
  FireService().updateMemo(
      reference: fireModel.reference!, json: updateModel.toJson());
  Navigator.of(context).pop(true);
},

완성된 화면의 모습(클릭해서 봐주세요)


전체 코드 

여기는 데이터 읽어오기, 수정하기로 가는 부분, 삭제하기, 저장하기 부분을 사용하는 부분이 구현되어 있습니다.  

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter3_train/firebase/fire_model.dart';
import 'package:flutter3_train/firebase/fire_service.dart';
import 'package:flutter3_train/screens/edit_screen.dart';

import '../util/logger.dart';

class HomePage extends StatefulWidget {
  HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  TextEditingController _inputController = TextEditingController();
  Future<List<FireModel>>? _future;

  @override
  void dispose() {
    _inputController.dispose();
    super.dispose();
  }

  @override
  void initState() {
    logger.d("initState");
    _future = FireService().getFireModel();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("Flutter & FireBase")),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          children: [
            Expanded(
                child: FutureBuilder<List<FireModel>>(
              future: FireService().getFireModel(),
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  List<FireModel> datas = snapshot.data!;
                  return ListView.builder(
                      itemCount: datas.length,
                      itemBuilder: (BuildContext context, int index) {
                        FireModel data = datas[index];
                        return Card(
                            child: ListTile(
                          title: Text("${data.motto}"),
                          subtitle: Text("${(data.date)!.toDate()}"),
                          trailing: IconButton(
                            icon: const Icon(Icons.delete),
                            onPressed: () {
                              logger.d(data.reference);
                              FireService().deleteMemo(data.reference!);
                              setState(() {});
                            },
                          ),
                          onLongPress: () {
                            Navigator.of(context).push(MaterialPageRoute(builder: (_){
                              return EditScreen(fireModel: data);
                            })).then((value){
                              if(value){
                                setState(() {});
                              }
                            });
                          },
                        ));
                      });
                } else {
                  logger.d("CircularProgressIndicator");
                  return const Center(child: CircularProgressIndicator());
                }
              },
            )),
            Row(
              children: [
                Expanded(
                    child: TextFormField(
                  controller: _inputController,
                  decoration: const InputDecoration(
                      hintText: "input message",
                      border: OutlineInputBorder(
                          borderSide: BorderSide(color: Colors.green))),
                )),
                TextButton(
                    onPressed: () async {
                      FireModel fireModel = FireModel(
                          motto: _inputController.text, date: Timestamp.now());

                      await FireService().createMemo(fireModel.toJson());
                      FireService().getFireModel();
                      _inputController.clear();
                      setState(() {});
                    },
                    child: const Icon(Icons.send)),
              ],
            ),
            const SizedBox(
              height: 30,
            )
          ],
        ),
      ),
    );
  }
}

여기는 데이터 읽어오기, 수정하기, 삭제하기, 저장하기가 클래스로 구현되어 있습니다. 

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter3_train/firebase/fire_model.dart';
import 'package:flutter3_train/util/logger.dart';

class FireService {
  // 싱글톤 패턴
  static final FireService _fireService = FireService._internal();

  factory FireService() => _fireService;

  FireService._internal();

  //Create
  Future createMemo(Map<String, dynamic> json) async {
    // 초기화
    await FirebaseFirestore.instance.collection("memo").add(json);
  }

  //READ
  Future<List<FireModel>> getFireModel() async {
    CollectionReference<Map<String, dynamic>> collectionReference =
        FirebaseFirestore.instance.collection("memo");
    logger.d("getFireModel1");
    QuerySnapshot<Map<String, dynamic>> querySnapshot =
        await collectionReference.orderBy("date").get();
    logger.d("getFireModel2");

    List<FireModel> mottos = [];
    for (var doc in querySnapshot.docs) {
      FireModel fireModel = FireModel.fromQuerySnapshot(doc);
      mottos.add(fireModel);
    }
    logger.d(mottos);
    return mottos;
  }

  //UPDATE
  Future updateMemo(
      {required DocumentReference reference, required Map<String, dynamic> json}) async{
    await reference.set(json);
  }

  //DELETE
  Future<void> deleteMemo(DocumentReference reference) async {
    await reference.delete();
  }
}

수정하기 부분 전체 코드

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter3_train/firebase/fire_model.dart';
import 'package:flutter3_train/firebase/fire_service.dart';
import 'package:flutter3_train/util/logger.dart';

class EditScreen extends StatelessWidget {
  final FireModel fireModel;

  EditScreen({Key? key, required this.fireModel}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    TextEditingController controller =
        TextEditingController(text: "${fireModel.motto}");
    logger.d(fireModel.motto);
    logger.d(fireModel.reference);

    return Scaffold(
      appBar: AppBar(title: const Text("EDIT SCREEN")),
      body: Row(
        children: [
          Expanded(
              child: TextFormField(
            controller: controller,
            decoration: const InputDecoration(
                hintText: "input message",
                border: OutlineInputBorder(
                    borderSide: BorderSide(color: Colors.green))),
          )),
          TextButton(
              onPressed: () {
                FireModel updateModel =
                    FireModel(motto: controller.text, date: Timestamp.now());
                FireService().updateMemo(
                    reference: fireModel.reference!, json: updateModel.toJson());
                Navigator.of(context).pop(true);
              },
              child: const Icon(Icons.send)),
        ],
      ),
    );
  }
}

이것으로 플러터와 파이어베이스에 데이터 저장하기 편을 마치도록 하겠습니다. 

댓글