前回は、Flutterのパッケージであるget_itとcloud_firestoreを使い、Firebaseのデータベースにデータを削除しました。

今回は、Firebase Cloud Firestoreのデータを更新します。

firebaseのコードは、前回までのコードを使用します。

import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

class FirebaseService {
  FirebaseAuth _auth = FirebaseAuth.instance;
  FirebaseFirestore _database = FirebaseFirestore.instance;

  FirebaseService();

  Future<bool> registerUser({
    required String email,
    required String password,
  }) async {
    try {
      UserCredential _userCredential = await _auth
          .createUserWithEmailAndPassword(email: email, password: password);
      return true;
    } catch (e) {
      print(e);
      return false;
    }
  }

  Future<bool> loginUser({
    required String email,
    required String password,
  }) async {
    try {
      UserCredential _userCredential = await _auth.signInWithEmailAndPassword(
          email: email, password: password);
      if (_userCredential.user != null) {
        return true;
      } else {
        return false;
      }
    } catch (e) {
      print(e);
      return false;
    }
  }

  Stream<QuerySnapshot> getBooks() {
    return _database
        .collection('books')
        .orderBy('timestamp', descending: true)
        .snapshots();
  }

  Future<bool> postBook({required String title, String? author}) async {
    try {
      await _database.collection('books').add(
        {
          'title': title,
          'author': author,
          'timestamp': Timestamp.now(),
        },
      );
      return true;
    } catch (e) {
      print(e);
      return false;
    }
  }

  Future<bool> deleteBook({required String docId}) async {
    try {
      await _database.collection('books').doc(docId).delete();
      return true;
    } catch (e) {
      print(e);
      return false;
    }
  }
}

まずは、Cloud Firestoreの単一データを取得するために、getBookを作成します。

単一データを取得するには、docにドキュメントIDを指定します。

Stream<DocumentSnapshot<Map<String, dynamic>>> getBook(String docId) {
  return _database.collection('books').doc(docId).snapshots();
}

次に、Cloud Firestoreのデータを更新するために、updateBookを作成します。

データを更新するには、updateを設定します。

Future<bool> updateBook(
      {required String docId, String? title, String? author}) async {
  try {
    await _database.collection('books').doc(docId).update(
      {
        'title': title,
        'author': author,
      },
    );

    return true;
  } catch (e) {
    print(e);
    return false;
  }
}

次に、更新画面を作成します。

import 'package:flutter/material.dart';

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

  @override
  State<UpdateBook> createState() => _UpdateBookState();
}

class _UpdateBookState extends State<UpdateBook> {
  double? _deviceWidth, _deviceHeight;

    final GlobalKey<FormState> _updateBookKey = GlobalKey<FormState>();

  String? _title;
  String? _author;

  @override
  Widget build(BuildContext context) {
    _deviceWidth = MediaQuery.of(context).size.width;
    _deviceHeight = MediaQuery.of(context).size.height;

    return Scaffold(
      body: SafeArea(
        child: Container(
          padding: EdgeInsets.symmetric(
            horizontal: _deviceWidth! * 0.05,
          ),
          child: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              mainAxisSize: MainAxisSize.max,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: [
                const Text(
                  '書籍編集',
                  style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
                ),
                Container(
                  height: _deviceHeight! * 0.2,
                  child: Form(
                    key: _updateBookKey,
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      mainAxisSize: MainAxisSize.max,
                      crossAxisAlignment: CrossAxisAlignment.center,
                      children: [
                        TextFormField(
                          decoration: const InputDecoration(hintText: 'タイトル'),
                          onSaved: (_value) {
                            setState(() {
                              _title = _value!;
                            });
                          },
                        ),
                        TextFormField(
                          decoration: const InputDecoration(hintText: '著者'),
                          onSaved: (_value) {
                            setState(() {
                              _author = _value;
                            });
                          },
                        ),
                      ],
                    ),
                  ),
                ),
                MaterialButton(
                  onPressed: () {},
                  minWidth: _deviceWidth! * 0.5,
                  height: _deviceHeight! * 0.06,
                  color: Colors.blueAccent,
                  child: const Text(
                    '更新',
                    style: TextStyle(
                        color: Colors.white, fontWeight: FontWeight.bold),
                  ),
                )
              ],
            ),
          ),
        ),
      ),
    );
  }
}

初期画面で指定した書籍を表示するために、controllerを設定します。

class _UpdateBookState extends State<UpdateBook> {
  double? _deviceWidth, _deviceHeight;

  FirebaseService? _firebaseService;

  final GlobalKey<FormState> _updateBookKey = GlobalKey<FormState>();

  String? _title;
  String? _author;

  TextEditingController _titleController = TextEditingController();
  TextEditingController _authorController = TextEditingController();

TextFormFieldcontrollerを指定します。

TextFormField(
    controller: _titleController,
    decoration:
        const InputDecoration(hintText: 'タイトル'),
    onSaved: (_value) {
      setState(() {
        _title = _value!;
      });
    },
  ),
  TextFormField(
    controller: _authorController,
    decoration:
        const InputDecoration(hintText: '著者'),
    onSaved: (_value) {
      setState(() {
        _author = _value;
      });
    },
  ),
],

get_itfirebase_serviceをインポートします。

import 'package:get_it/get_it.dart';
import 'package:test_form/services/firebase_service.dart';

FirebaseServiceの変数を作成します。

class _LoginState extends State<Login> {
  double? _deviceWidth, _deviceHeight;

  FirebaseService? _firebaseService;

initStateを作成し、GetItgetFirebaseServiceを呼び出します。

@override
void initState() {
  super.initState();
  _firebaseService = GetIt.instance.get<FirebaseService>();
}

一覧を作成するために、StreamBuilderを設定します。

streamは、_firebaseServicegetBook()を指定します。

builderは、contextsnapshotを設定します。

snapshotdataが存在する場合は一覧を表示し、存在しない場合はインジケータを表示します。

他画面から遷移する場合、getBook内の『'LznyXT6qZyflKSvkgZ4z'』は、ドキュメントIDを指定するといいでしょう。

child: Container(
  padding: EdgeInsets.symmetric(
    horizontal: _deviceWidth! * 0.05,
  ),
  child: Center(
    child: StreamBuilder(
      stream: _firebaseService!.getBook('LznyXT6qZyflKSvkgZ4z'),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData) {
          return Column(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            mainAxisSize: MainAxisSize.max,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const Text(
                '書籍編集',
                style: TextStyle(
                    fontSize: 24, fontWeight: FontWeight.bold),
              ),
              Container(
                height: _deviceHeight! * 0.2,
                child: Form(
                  key: _updateBookKey,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceAround,
                    mainAxisSize: MainAxisSize.max,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: [
                      TextFormField(
                        controller: _titleController,
                        decoration:
                            const InputDecoration(hintText: 'タイトル'),
                        onSaved: (_value) {
                          setState(() {
                            _title = _value!;
                          });
                        },
                      ),
                      TextFormField(
                        controller: _authorController,
                        decoration:
                            const InputDecoration(hintText: '著者'),
                        onSaved: (_value) {
                          setState(() {
                            _author = _value;
                          });
                        },
                      ),
                    ],
                  ),
                ),
              ),
              MaterialButton(
                onPressed: (){},
                minWidth: _deviceWidth! * 0.5,
                height: _deviceHeight! * 0.06,
                color: Colors.blueAccent,
                child: const Text(
                  '更新',
                  style: TextStyle(
                      color: Colors.white, fontWeight: FontWeight.bold),
                ),
              )
            ],
          );
        } else {
          return const Center(
            child: CircularProgressIndicator(),
          );
        }
      },
    ),
  ),
),

_titleController.textsnapshot.data?['title']_authorController.textsnapshot.data?['author']を指定します。

それぞれ、データがなければ、空データが入るようにします。

child: StreamBuilder(
  stream: _firebaseService!.getBook('LznyXT6qZyflKSvkgZ4z'),
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    if (snapshot.hasData) {
      _titleController.text = snapshot.data?['title'] != null
          ? snapshot.data['title']
          : '';
      _authorController.text = snapshot.data?['author'] != null
          ? snapshot.data['author']
          : '';

最後に、更新ボタンを機能させるために、_update関数を作成します。

先ほど作成したupdateBookを使用します。

updateBookには、ドキュメントIDと_title_authorを渡すようにします。

void _update(
  docId,
) async {
  _updateBookKey.currentState!.save();

  bool _result = await _firebaseService!
      .updateBook(docId: docId!, title: _title, author: _author);
  print('更新結果: $_result');
}

MaterialButtononPressed_updateを設定します。

MaterialButton(
  onPressed: () => _update('LznyXT6qZyflKSvkgZ4z'),
  minWidth: _deviceWidth! * 0.5,
  height: _deviceHeight! * 0.06,
  color: Colors.blueAccent,
  child: const Text(
    '更新',
    style: TextStyle(
        color: Colors.white, fontWeight: FontWeight.bold),
  ),
)

では、動作確認します。

画面を確認すると、

image2

image3

getBookで指定した単一データが表示されました。

では、タイトルを編集して、更新ボタンをタップしてみます。

image4

image5

更新結果:tureが返ってきました。

FirebaseのCloud Firestoreを確認すると、

image6

titleが更新されていました。

ブログ一覧