1
votes

I am getting a NoSuchMethodError when trying to perform a transaction update on my Firestore collection.

Receiver: null
Tried calling: cast<String, dynamic>()
#0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
#1      MethodChannel.invokeMapMethod (package:flutter/src/services/platform_channel.dart:331:19)
<asynchronous suspension>
#2      Firestore.runTransaction (file:///Users/wready/dev_tools/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.9.7+2/lib/src/firestore.dart:114:10)
<asynchronous suspension>
#3      _HomePageState._buildListItem.<anonymous closure> (package:maas_app/pages/home_page.dart:204:43)
#4      _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:513:14)
#5      _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:568:30)
#6      GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:120:24)
#7      TapGestureRecognizer._checkUp (package:flutter/src/gestures/t<…>

It is actually updating fine on the backend and is displaying correctly on my simulator as well. But clearly I am missing something here. I am not sure why it is receiving this error since every print statement I've tried shows no null objects/references.

Any help is greatly appreciated!!!

Before onTap print:

flutter: Todo{subject: make flutter awesome, completed: false, userId: [email protected], reference: Instance of 'DocumentReference'}

After onTap print:

flutter: Todo{subject: make flutter awesome, completed: true, userId: [email protected], reference: Instance of 'DocumentReference'}

I've tried different variations of the transaction.update I've seen at https://codelabs.developers.google.com/codelabs/flutter-firebase/index.html#10 and https://medium.com/flutter-community/simple-recipes-app-made-in-flutter-firestore-f386722102da

Both perform the update in Firestore and UI correctly but throw same exception.

The onTap section is where it is failing :

  Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
    final todo = Todo.fromSnapshot(data);

    print(todo);

    return Padding(
      key: ValueKey(todo.toString()),
      padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
      child: Container(
        decoration: BoxDecoration(
          border: Border.all(color: Colors.grey),
          borderRadius: BorderRadius.circular(5.0),
        ),
        child: ListTile(
          title: Text(todo.subject),
          trailing: Text(todo.completed.toString()),
          onTap: () => Firestore.instance.runTransaction((Transaction transaction) async {
            final DocumentSnapshot freshSnapshot = await transaction.get(todo.reference);
            final Todo fresh = Todo.fromSnapshot(freshSnapshot);

            await transaction.update(todo.reference, {'completed': !fresh.completed});
          }),
        ),
      ),
    );
  }

My Todo model:

import 'package:cloud_firestore/cloud_firestore.dart';

class Todo {
  final String subject;
  final bool completed;
  final String userId;
  final DocumentReference reference;

  Todo.fromMap(Map<String, dynamic> map, {this.reference})
      : assert(map['userId'] != null),
        assert(map['subject'] != null),
        assert(map['completed'] != null),
        userId = map['userId'],
        subject = map['subject'],
        completed = map['completed'];

  Todo.fromSnapshot(DocumentSnapshot snapshot)
      : this.fromMap(snapshot.data, reference: snapshot.reference);

  @override
  String toString() {
    return 'Todo{subject: $subject, completed: $completed, userId: $userId, reference: $reference}';
  }

}

UPDATE: Tried update without even using models with approach from https://www.youtube.com/watch?v=DqJ_KjFzL9I . Still getting same error :(

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

class TodoListWidget extends StatelessWidget {

  TodoListWidget({this.firestore});

  final Firestore firestore;

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: firestore.collection('todo').snapshots(),
      builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
        if (!snapshot.hasData) return const Text('Loading...');
        final int messageCount = snapshot.data.documents.length;
        return ListView.builder(
          itemCount: messageCount,
          itemBuilder: (_, int index) {
            final DocumentSnapshot document = snapshot.data.documents[index];
            return ListTile(
              title: Text(document['subject'] ?? '<No subject retrieved>'),
              trailing: Text(document['completed']?.toString() ?? '<No completed retrieved>'),
              onTap: () => Firestore.instance.runTransaction((Transaction transaction) async {
                final DocumentSnapshot freshSnapshot = await transaction.get(document.reference);

                await transaction.update(freshSnapshot.reference, {
                  'completed': !freshSnapshot.data['completed'],});
              }),

            );
          },
        );
      },
    );
  }
}
2

2 Answers

1
votes

I am having the same issue, looks like a bug. That causes the problem with async functions, transactions always callback that exception

EDIT: I've tried to downgrade to 0.9.6 and there is no issue.

0
votes

I was facing the same issue on 0.9.7

Upgrading to 0.9.11 fixed it for me while downgrading to 0.9.6 didn't work.