質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.34%

【Flutter】DatatableのcheckboxがUI上でチェックされない

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 443

AAA_AAA

score 3

前提・問題点

現在、Flutter+Firebaseを利用してアプリ開発について学習を行っています。
その中でCloudFirestoreから持ってきたデータをDatatableに反映しているのですが、
Datatablecheckboxがlogをみるとselectedがタップ時はTrueになっているので
反応はしているのですが、UI上でcheckboxにチェックつかず困っています。

なので、選択してから削除ボタンを押すと該当のデータは削除されます。
しかし、UI上にチェックがついていないので選択されたかどうかがわからない状態にあります。

解決方法をご存知の方がいましたら回答いただけると助かります。

補足情報(FW/ツールのバージョンなど)

使用したもの
cloud_firestore: ^0.13.7

以下実装したコード

import 'dart:math';
import 'package:card_manager/add_deck_page.dart';
import 'package:card_manager/add_record_page.dart';
import 'package:card_manager/card_page.dart';
import 'package:card_manager/main.dart';
import 'package:card_manager/page_manager.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:provider/provider.dart';

import 'login_page.dart';

class RecordPage extends StatefulWidget {
  final String email;
  final String name;

  BattleRecordPage(this.name, this.email);

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

class _RecordPage extends State<RecordPage> {

  List<DocumentSnapshot> selectedRecords;


  List<DocumentSnapshot> documents;


  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    selectedRecords = [];

  }

  onSelectedRow(bool selected, DocumentSnapshot document) async {
    setState(() {
      if (selected) {
        selectedRecords.add(record);
      } else {
        selectedRecords.remove(document);
      }
    });
  }

  deleteSelected() async {
    setState(() {
      if (selectedRecords.isNotEmpty) {
        List<DocumentSnapshot> temp = [];
        temp.addAll(selectedRecords);
        for (DocumentSnapshot record in temp) {
          Firestore.instance
              .collection("Records")
              .document(record.documentId)
              .delete();
          selectedRecords.remove(record);
        }
      }
    });
  }
  Widget recordData(documents) =>
      DataTable(
          showCheckboxColumn: true,
          columns: const <DataColumn>[
            DataColumn(
                label: Text(
                  "email",
                  style: TextStyle(fontStyle: FontStyle.italic),
                ),
                numeric: false),
            DataColumn(
                label: Text(
                  "name",
                  style: TextStyle(fontStyle: FontStyle.italic),
                ),
                numeric: false),

          ],
          rows: documents
              .map<DataRow>((document) =>
              DataRow(
                  selected: selectedRecords.contains(document),
                  onSelectChanged: (b) {
                      onSelectedRow(b, document);
                  },
                  cells: <DataCell>[
                        DataCell(Text(document["email"]),
                            showEditIcon: false, placeholder: true),
                        DataCell(Text(document["name"]),
                            showEditIcon: false, placeholder: false),
                  ]))
              .toList());


  @override
  Widget build(BuildContext context) {
    //ユーザ情報
    final UserState userState = Provider.of<UserState>(context);

    final FirebaseUser user = userState.user;
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("Record"),
        actions: <Widget>[
          IconButton(
            icon: Icon(Icons.add),
            onPressed: () async {
              Navigator.pushNamed(context, AddRecord.routeName,
                  arguments: AddRecord(widget.email, widget.name));
            },
          ),
          IconButton(
            icon: Icon(Icons.delete),
            onPressed: () async {
              await deleteSelected();
            },
          )
        ],
      ),
      body: Column(
        children: <Widget>[
          Expanded(
            //非同期処理の結果をもとにWidget作成
            child: StreamBuilder<QuerySnapshot>(
              //非同期処理結果→future
                stream: Firestore.instance
                    .collection("Records")
                    .where("uid", isEqualTo: user.uid)
                    .where("name", isEqualTo: widget.name)
                    .orderBy("date")
                    .snapshots(),
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    documents =
                        snapshot.data.documents;
                    return SingleChildScrollView(
                        scrollDirection: Axis.vertical,
                        child: FittedBox(child: recordData(documents)));
                  }
                  return Center(
                    child: Text("読み込み中..."),
                  );
                }),
          )
        ],
      ),
    );
  }
}
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

以下のように、ドキュメントのidで比較するようにしてみてください。
※ FireStoreのバージョンが古い場合はdocumentIDという名前かもしれません。

DataRow(
  selected: selectedRecords.any((record) => record.id == document.id),
  onSelectChanged: ...
  cells: ...

あと、以下の部分のrecordという変数はdocumentの間違いでは無いでしょうか?

  onSelectedRow(bool selected, DocumentSnapshot document) async {
    setState(() {
      if (selected) {
        selectedRecords.add(record);
      } else {
        selectedRecords.remove(document);
      }
    });
  }

追記(09/02/21:00): チェックが外れない問題の修正方法
配列から削除するのにremoveを使うと、DocumentSnapshotの場合、同じインスタンスかどうかで判定されてしまいます。
代わりにremoveWhereを使ってidを比較して同じものを削除するようにしてみてください。

  onSelectedRow(bool selected, DocumentSnapshot document) async {
    setState(() {
      if (selected) {
        selectedRecords.add(document);
      } else {
        selectedRecords.removeWhere((record) => record.id == document.id);
      }
    });
  }

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/09/02 22:25 編集

    ありがとうございます。無事動作しました。

    自分が無知なもので少しお聞きしたいのですが、
    checkが入る場合と入らない場合のどちらに関しても
    DocumentSnapshotだとインスタンスで判断すると
    結果がfalseと帰ってきてcheckが正常に動作しないのは何故でしょうか?

    お手数おかけしますが回答いただけると幸いです。

    キャンセル

  • 2020/09/02 23:30

    おそらくListのaddメソッドが、同じ値を持った別オブジェクトを生成して配列に格納するためです。
    同じ値を持っていますが、別物なので結果がfalseになってしまっていたのだと思います。

    キャンセル

  • 2020/09/02 23:46

    ありがとうございます。理解できました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る