1
votes

So I tried creating a model classes similar to rails, laravel or other frameworks so that I could organize my code better and I wanted to add instance methods to save data to firebase here is my class. However, for some reason when I call the save method on my event class. I get this error MissingPluginException(No implementation found for method DocumentReference#setData on channel plugins.flutter.io/cloud_firestore).

I tried running flutter clean, after googling, upgrading flutter, uninstalling the app, and running packages get and nothing worked. Finally I tried just creating normal function inside of my widget component to create a new document and add data. The function worked fine without an error. Also, yes, I did the appropriate imports of importing cloud firestore into my event class as well geoflutterfire. Why am I getting the error and is there a way to organize my code? Do firestore methods not work in dart files that aren't widgets that inherit from stateless widget or statfefull widget? I tried importing foundation and material dart packages and they were both greyed out with Firestore and my privateEvent class obviously not using it.

  final bool feedbackLocationOrActivity;
  final String id;
  final bool feedbackTimeAndDate;
  final String name;
  final String mediaUrl;
  final String address;
  final DateTime startTime;
  final DateTime endTime;
  List categories;
  final String creatorId;
  final String groupId;
  final GeoFirePoint location;
  List coHosts;
  final String details;
  final bool guestsCanInviteFriends;

  PrivateEvent(
      {this.feedbackLocationOrActivity,
      this.id,
      this.feedbackTimeAndDate,
      this.name,
      this.mediaUrl,
      this.address,
      this.startTime,
      this.endTime,
      this.categories,
      this.creatorId,
      this.location,
      this.coHosts,
      this.guestsCanInviteFriends,
      this.details,
      this.groupId});

  factory PrivateEvent.fromDocument(DocumentSnapshot doc) {
    return PrivateEvent(
        id: doc['id'],
        feedbackLocationOrActivity: doc['feedbackLocationOrActivity'],
        feedbackTimeAndDate: doc['feedbackTimeAndDate'],
        name: doc['name'],
        mediaUrl: doc['mediaUrl'],
        address: doc['address'],
        startTime: doc['startTime'],
        endTime: doc['endTime'],
        categories: doc['categories'],
        creatorId: doc['creatorId'],
        groupId: doc['groupId'],
        coHosts: doc['coHosts'],
        guestsCanInviteFriends: doc['guestsCanInviteFriends'],
        details: doc['details'],
        location: doc['location']);
  }

  save() async {
    return Firestore.instance
        .collection('privateEvents')
        .document(this.groupId)
        .collection("events")
        .add({
      "id": this.id,
      "feedbackLocationOrActivity": this.feedbackLocationOrActivity,
      "feedbackTimeAndDate": this.feedbackTimeAndDate,
      "name": this.name,
      "mediaUrl": this.mediaUrl,
      "address": this.address,
      "startTime": this.startTime,
      "endTime": this.endTime,
      "categories": FieldValue.arrayUnion(this.categories),
      "creatorId": this.creatorId,
      "location": this.location.data,
      "details": this.details,
      "coHosts": FieldValue.arrayUnion(this.coHosts),
      "guestsCanInviteFriends": this.guestsCanInviteFriends
    }).then((response) {
      response.updateData({"id": response.documentID});
      return true;
    }).catchError((onError) {
      print("this is the error $onError");
      return false;
    });
  }
}

The save method is the method that should save it to the database however it gets an error.

Here is where I call it.

createEvent({screenWidth, screenHeight, isLandscape}) async {
    setState(() {
      loading = true;
    });
    final String mediaUrl = await uploadImage(file);
    if (mediaUrl.isEmpty || mediaUrl == null) {
      setState(() {
        loading = false;
      });
      eventTimeWarning(
          screenWidth: screenWidth,
          screenHeight: screenHeight,
          isLandscape: isLandscape,
          warningMessage:
              "Your image didn't upload properly. There could be a problem with your internet connection. Please try again");
      return;
    }
    PrivateEvent privateEvent = PrivateEvent(
        feedbackTimeAndDate: feedbackTimeAndDate,
        feedbackLocationOrActivity: feedbackLocationOrActivity,
        name: eventName,
        mediaUrl: mediaUrl,
        address: eventAddress,
        startTime: eventStartTimeAndDate,
        endTime: eventEndTimeAndDate,
        categories: selectedCategories(),
        creatorId: Provider.of<UserData>(context).getUserId,
        location: eventLocation,
        guestsCanInviteFriends: guestsCanInviteFriends,
        details: detailsController.text.trim(),
        groupId:
            Provider.of<PrivateGroupNormalData>(context).getGroupId); 

    final bool eventUploadSuccess = await sendEventInfo();
    if (!eventUploadSuccess) {
      setState(() {
        eventTimeWarning(
            screenWidth: screenWidth,
            screenHeight: screenHeight,
            isLandscape: isLandscape,
            warningMessage:
                "There was a problem creating your event. Please, check your internet connection and try again.");
        loading = false;
      });
      return;
    }
    print("EVENT CREATED SUCCESSFULLY!");
  }

As I said before. The above doesn't work. However On creating a function within the widget. The data is added to the database and there is no missingexception error.

Here is the working version.

Future<bool> sendEventInfo({String mediaUrl}) {
    return Firestore.instance
        .collection('privateEvents')
        .document(Provider.of<PrivateGroupNormalData>(context).getGroupId)
        .collection("events")
        .add({
      "feedbackLocationOrActivity": this.feedbackLocationOrActivity,
      "feedbackTimeAndDate": this.feedbackTimeAndDate,
      "name": this.eventName,
      "mediaUrl": mediaUrl,
      "address": eventAddress,
      "startTime": eventStartTimeAndDate,
      "endTime": eventEndTimeAndDate,
      "categories": selectedCategories(),
      "creatorId": Provider.of<UserData>(context).getUserId,
      "location": eventLocation.data,
      "details": detailsController.text.trim(),
      "coHosts": FieldValue.arrayUnion(),
      "guestsCanInviteFriends": this.guestsCanInviteFriends
    }).then((response) {
      response.updateData({"id": response.documentID});
      return true;
    }).catchError((onError) {
      print("this is the error $onError");
      return false;
    });
  } 

All I do is replace the call to instance method with the call to the above function and now it works fine without the missing plugin error.
1
remove the return from front of Firestore.instance - Viren V Varasadiya
Hey. I will give a run without the return. However, if I remove the return, how can I get back from the function whether the upload was successful or not? As you can see with sendEventInfo function that returns a Future of a boolean on whether or not the upload was successful there was no issue. - Chris Matthews
So removing the return statement did not work. Did it work for you? To replicate. Create a class separate from your widget and create a save instance method that allows you to save an instance of the class to the firestore. Then create an object of that class that you created in a separate widget after importing it into the widget. Then try calling the instance method of save and see what happens. Additionally, implicitly use the Firestore setData method by creating a custom document ID at the top level as you can see that I have with a collection nested underneath. - Chris Matthews

1 Answers

0
votes

The answer is that I had to make my Firestore Instance a static instance to be able to access it properly.