Getting started with Appwrite Cloud and Flutter

Femi-ige Muyiwa - Jun 5 '23 - - Dev Community

Isn’t it nice to have all the traditional backend features on the web? Appwrite cloud alleviates the need to manage a server. Appwrite cloud is a backend as a service (BaaS) with all the necessary APIs to build your modern application. These APIs assist in building client and server-side applications. A use case of Appwrite is the Database API, which assists in implementing CRUD (create, read, update, delete) features in your application.

This article will show you how to use an input element to create, store, view and delete text in Flutter using Appwrite.

Prerequisites

To follow along with this tutorial, the following are required:

  • Xcode (with developer account for Mac users)
  • iOS Simulator, Android Studio, or Chrome web browser to run the application
  • Appwrite cloud access. It is currently in beta testing.

Creating an Appwrite project

You can apply to the Appwrite cloud to access the private beta. Once you access Appwrite’s cloud private beta, create a project and fill in the project's name and id; otherwise, use Appwrite locally with Docker or DigitalOcean droplet.

Create Project

Also, you will need a database collection to perform CRUD operations. Head to Databases, select Create Database, and fill in the database name and ID. After, create a new collection by selecting Create collection and filling in the subsequent name and ID.

Databases
Create databases
Create collections

It is necessary to have parameters to hold data within your collection. Thus, head to the attributes section within the collection created earlier and add the attributes in the following table to the collection:

Attribute key Attribute type
title String
subtitle String

Finally, head to the collection settings section and set the collection and document level permission to role:any and check all the CRUD permissions. These permissions allow anyone to create, read, update, and delete documents from the collection.

Update permission 1
Update permission 2

Cloning the UI template

This section uses a UI template containing user registration and login code. Let’s clone the repository specified in the prerequisites. Check out the official GitHub docs to learn more about cloning a repository.

GitHub clone 1
GitHub clone 2

After cloning the UI to your local storage, open it in your preferred code editor and run the command below:



flutter pub get


Enter fullscreen mode Exit fullscreen mode

This command obtains all the dependencies listed in the pubspec.yaml file in the current working directory and their transitive dependencies. Next, run the command flutter run, and your application should look like the image below:

clone result

The lib directory tree should look like this:



    lib/
    ├─ auth/
      ├─ app_provider.dart
    ├─ model/
      ├─ documentmodel.dart
    ├─ pages/
      ├─ components/
        ├─ add_item_modal.dart
        ├─ edit_item_modal.dart
      ├─ home.dart
    ├─ main.dart


Enter fullscreen mode Exit fullscreen mode

Explaining the UI and functionalities

Functionalities
Before beginning, create a file app_constants.dart to store important constants from Appwrite. Update the app_constants.dart with the code below:


 javascript
class Appconstants {
  static const String projectid = "<projectID>";
  static const String endpoint = "<cloud endpoint>";
  static const String dbID = "<database ID>";
  static const String collectionID = "<collection ID>";
}


Enter fullscreen mode Exit fullscreen mode

The project utilizes the Provider package for its state management purposes. Thus, the app_provider.dart file defines a class named AppProvider that is implementing ChangeNotifier. The AppProvider class contains various methods for creating, listing, updating, and removing documents in a database using the Appwrite package.

In the code above, the AppProvider class implements the ChangeNotifier class to handle changes in your application’s state. The Client class instance, named client, is tasked with communicating with the Appwrite API.

The Account and Databases instances communicate with the account and database API. This allows you to create a user account on the client side and perform the CRUD operations.

The code above uses the initialize method to set up the client instance by setting the endpoint and project and creating an anonymous session for the user.

To utilize the CRUD operations in Appwrite, here is a summary of the document-based methods in the code:

  • createDocument method takes in newTitle, newSubtitle, and context parameters to create a new document in the specified database and collection. It then adds the new document to the list of documents and closes the add document screen.
  • listDocument method lists all the documents in the specified database and collection. It maps the returned list of documents to a list of ListItem objects and sets the _listItem variable to this list.

You can use a model class to map the JSON when getting a list of documents from Appwrite. Thus, add the code below in documentmodel.dart file


 javascript
class UserFields {
  static const String id = "\$id";
  static const String title = "title";
  static const String subtitle = "subtitle";
}
class ListItem {
  String? id;
  String? title;
  String? subtitle;
  ListItem({
    required this.id,
    required this.title,
    required this.subtitle,
  });
  ListItem.fromJson(Map<String, dynamic> json) {
    id = json[UserFields.id];
    title = json[UserFields.title];
    subtitle = json[UserFields.subtitle];
  }
  Map<String, dynamic> toJson() {
    final Map<String, dynamic> data = <String, dynamic>{};
    data[UserFields.id] = id;
    data[UserFields.title] = title;
    data[UserFields.subtitle] = subtitle;
    return data;
  }
}


Enter fullscreen mode Exit fullscreen mode
  • the updateDocument method takes in documentId, updateTitle, and updateSubtitle parameters to update the specified document in the database with the new title and subtitle.
  • the removeDocument method takes in documentId and index parameters to delete the specified document from the database and remove it from the list of documents.

Overall, the AppProvider class provides a way to manage documents in an Appwrite database in a Flutter application.

UI (User interface)
The pages folder consists of the entirety of the user interface. The user interface consists of a centered container whose primary action is to display a list of created items. The Container has an ElevatedButton widget with an onPressed action displaying a modal. This displayed modal consists of a formfield (input and button) that takes values to create an item.

To perform an update action, wrap the list in an Inkwell widget and attach an onTap property that shows an editable modal that updates the list and the document on Appwrite.


 javascript
//Home.dart 

Widget appContainer(BuildContext context, state) {
  return Container(
      height: MediaQuery.of(context).size.height,
      width: MediaQuery.of(context).size.width,
      margin: const EdgeInsets.only(left: 50, right: 50, top: 50),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25.0),
        color: const Color.fromARGB(238, 238, 232, 198),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Padding(
            padding: const EdgeInsets.all(20.0),
            child: ElevatedButton.icon(
              onPressed: () {
                // Handle the tap event by displaying a dialog box where the user can edit the data
                showDialog(
                  context: context,
                  builder: (BuildContext context) {
                    // Return the dialog widget
                    return const AddItemDialog();
                  },
                );
              },
              icon: const Icon(
                Icons.add,
                size: 24.0,
              ),
              label: const Text("Add Item"),
            ),
          ),
          items(state)
        ],
      ));
}
Widget items(state) {
  return Expanded(
      child: Container(
          child: state.listItem.isEmpty
              ? const Center(
                  child: Text(
                    "No items found",
                    style: TextStyle(fontWeight: FontWeight.w800),
                  ),
                )
              : listContainer(state)));
}
Widget listContainer(state) {
  return ListView.builder(
    itemCount: state.listItem.length,
    itemBuilder: (BuildContext context, int index) {
      return InkWell(
        onTap: () {
          // Handle the tap event by displaying a dialog box where the user can edit the data
          showDialog(
            context: context,
            builder: (BuildContext context) {
              // Return the dialog widget
              return EditListItemDialog(
                item: state.listItem[index],
                onSave: (ListItem editedItem) {
                  // Update the item in the list with the edited data
                  state.listItem[index] = editedItem;
                  // Rebuild the UI to reflect the updated data
                  setState(() {});
                },
              );
            },
          );
        },
        child: ListTile(
          title: Text(state.listItem[index].title),
          subtitle: Text(state.listItem[index].subtitle),
          trailing: IconButton(
            icon: const Icon(Icons.delete),
            onPressed: () =>
                state.removeReminder(state.listItem[index].id, index),
          ),
        ),
      );
    },
  );
}


Enter fullscreen mode Exit fullscreen mode

Add item AlertDialog

Edit/Update item AlertDialog

When you run the application, your result should look like the GIF below:

result

Conclusion

Though still in beta testing, Appwrite Cloud is a game-changer, enabling the creation of backend functionalities swiftly and easily while providing the same benefits as using Appwrite locally. This tutorial has shown how to create CRUD features using the Appwrite cloud and Flutter.

Resources

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .