Home > Back-end >  Flutter/dart:: Adding a new field to class causing an error
Flutter/dart:: Adding a new field to class causing an error

Time:09-30

I added a new field to the class CloudNote, now I am getting an error! I am getting the error when the app is trying to display a list.

Here is all my code without adding the field :: https://github.com/casas1010/flutter_firebase_vendor_management

I know its a simple issue, but I have tried to troubleshoot this for like an hour and have not made any progress

CloudNote class::

import 'package:cloud_firestore/cloud_firestore.dart';
import '/services/cloud/cloud_storage_constants.dart';
import 'package:flutter/foundation.dart';

/*
https://youtu.be/VPvVD8t02U8?t=87934
*/

@immutable
class CloudNote {
  final String documentId;
  final String jobCreatorId;
  final String jobDescription;
  final String jobState;        // I added this
  const CloudNote({
    required this.documentId,
    required this.jobCreatorId,
    required this.jobDescription,
    required this.jobState,      // I added this
  });

  // acts as constructor
  CloudNote.fromSnapshot(QueryDocumentSnapshot<Map<String, dynamic>> snapshot)
      : documentId = snapshot.id,
        jobCreatorId = snapshot.data()[jobCreatorIdColumn],
        jobState = snapshot.data()[jobStateColumn],           // I added this
        jobDescription = snapshot.data()[jobDescriptionColumn] as String;
}

notes view ::

import 'package:flutter/material.dart';
import '/constants/routes.dart';
import '/enums/menu_action.dart';
import '/services/auth/auth_service.dart';
import '/services/cloud/cloud_note.dart';
import '/services/cloud/firebase_cloud_storage.dart';
import '/utilities/dialogs/logout_dialog.dart';
import '/views/notes/notes_list_view.dart';

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

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

class _NotesViewState extends State<NotesView> {
  late final FirebaseCloudStorage _notesService;
  String get userId => AuthService.firebase().currentUser!.id;

  @override
  void initState() {
    _notesService = FirebaseCloudStorage();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Your jobs'),
        actions: [
          IconButton(
            onPressed: () {
              Navigator.of(context).pushNamed(createOrUpdateNoteRoute);
            },
            icon: const Icon(Icons.add),
          ),
          PopupMenuButton<MenuAction>(
            onSelected: (value) async {
              switch (value) {
                case MenuAction.logout:
                  final shouldLogout = await showLogOutDialog(context);
                  if (shouldLogout) {
                    await AuthService.firebase().logOut();
                    Navigator.of(context).pushNamedAndRemoveUntil(
                      loginRoute,
                      (_) => false,
                    );
                  }
              }
            },
            itemBuilder: (context) {
              return const [
                PopupMenuItem<MenuAction>(
                  value: MenuAction.logout,
                  child: Text('Log out'),
                ),
              ];
            },
          )
        ],
      ),
      body: StreamBuilder(
        stream: _notesService.allNotes(jobCreatorId: userId),
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.waiting:
            case ConnectionState.active:
              if (snapshot.hasData) {
                final allNotes = snapshot.data as Iterable<CloudNote>;
                return NotesListView(
                  notes: allNotes,
                  onDeleteNote: (note) async {
                    await _notesService.deleteNote(documentId: note.documentId);
                  },
                  onTap: (note) {
                    Navigator.of(context).pushNamed(
                      createOrUpdateNoteRoute,
                      arguments: note,
                    );
                  },
                );
              } else {
                return const CircularProgressIndicator();
              }
            default:
              return const CircularProgressIndicator();
          }
        },
      ),
    );
  }
}

Error

The following _TypeError was thrown building NotesListView(dirty):
type 'Null' is not a subtype of type 'String'

The relevant error-causing widget was
NotesListView
lib/…/notes/notes_view.dart:72
When the exception was thrown, this was the stack
#0      new CloudNote.fromSnapshot
package:ijob_clone_app/…/cloud/cloud_note.dart:26
#1      FirebaseCloudStorage.allNotes.<anonymous closure>.<anonymous closure>
package:ijob_clone_app/…/cloud/firebase_cloud_storage.dart:39
#2      MappedListIterable.elementAt (dart:_internal/iterable.dart:413:31)
#3      ListIterator.moveNext (dart:_internal/iterable.dart:342:26)
#4      WhereIterator.moveNext (dart:_internal/iterable.dart:438:22)
#5      Iterable.length (dart:core/iterable.dart:497:15)
#6      NotesListView.build
package:ijob_clone_app/…/notes/notes_list_view.dart:26
#7      StatelessElement.build
package:flutter/…/widgets/framework.dart:4949
#8      ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4878
#9      Element.rebuild
package:flutter/…/widgets/framework.dart:4604
#10     ComponentElement._firstBuild
package:flutter/…/widgets/framework.dart:4859
#11     ComponentElement.mount
package:flutter/…/widgets/framework.dart:4853
#12     Element.inflateWidget
package:flutter/…/widgets/framework.dart:3863
#13     Element.updateChild
package:flutter/…/widgets/framework.dart:3586
#14     ComponentElement.performRebuild
package:flutter/…/widgets/framework.dart:4904
#15     StatefulElement.performRebuild
package:flutter/…/widgets/framework.dart:5050
#16     Element.rebuild
package:flutter/…/widgets/framework.dart:4604
#17     BuildOwner.buildScope
package:flutter/…/widgets/framework.dart:2667
#18     WidgetsBinding.drawFrame
package:flutter/…/widgets/binding.dart:882
#19     RendererBinding._handlePersistentFrameCallback
package:flutter/…/rendering/binding.dart:378
#20     SchedulerBinding._invokeFrameCallback
package:flutter/…/scheduler/binding.dart:1175
#21     SchedulerBinding.handleDrawFrame
package:flutter/…/scheduler/binding.dart:1104
#22     SchedulerBinding._handleDrawFrame
package:flutter/…/scheduler/binding.dart:1015
#23     _invoke (dart:ui/hooks.dart:148:13)
#24     PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:318:5)
#25     _drawFrame (dart:ui/hooks.dart:115:31)
════════════════════════════════════════════════════════════════════════════════

NotesListView ::

import 'package:flutter/material.dart';
import '/services/cloud/cloud_note.dart';
import '/utilities/dialogs/delete_dialog.dart';
/*
source: https://www.youtube.com/watch?v=VPvVD8t02U8&t=59608s
class creation :: 22:02:54
 */

typedef NoteCallback = void Function(CloudNote note);

class NotesListView extends StatelessWidget {
  final Iterable<CloudNote> notes; // list of notes
  final NoteCallback onDeleteNote;
  final NoteCallback onTap;

  const NotesListView({
    Key? key,
    required this.notes,
    required this.onDeleteNote,
    required this.onTap,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: notes.length,
      itemBuilder: (context, index) {
        final note =
            notes.elementAt(index); // current note whose data we are returning
        return ListTile(
          onTap: () {
            onTap(note);
          },
          title: Text(
            note.jobDescription,
            maxLines: 1,
            softWrap: true,
            overflow: TextOverflow.ellipsis,
          ),
          trailing: IconButton(
            onPressed: () async {
              final shouldDelete = await showDeleteDialog(context);
              if (shouldDelete) {
                onDeleteNote(note);
              }
            },
            icon: const Icon(Icons.delete),
          ),
        );
      },
    );
  }
}

CodePudding user response:

This happens if you forget to update your Firestore entries. Atleast one of your CloudNote entries in Firestore does not have the field jobState. That's why Firestore returns a Null value. But it tries to map to String which leads to an exception.

CodePudding user response:

Make sure to rerun the project. or flutter clean and then flutter run

  • Related