Multi-user “list” management on Firebase

Hi everyone :partying_face:

Recently, @Carlos_Alberto_Leonel needed a method to manage a list on Firebase.
I suggested the classic approach,

  • saving the list in a variable,
  • adding an element,
  • and sending the updated list back

but I expressed my concern about using such a method on a list where multiple people can add elements.

Let’s start with the basics

A list that we send to Firebase using the Web component will be interpreted as a dictionary with keys 0, 1, 2, and so on.

Which will, in fact, appear as a list.

"ClassicList": [
        "a",
        "b",
        "c"
      ]

(We can add an element to the list by passing a key:value pair as lengthOfList+1:value)

As mentioned earlier, this method works almost perfectly as long as it’s a static list or modified by a single user.
“Almost perfectly” because if we ever delete a specific index using the Web Delete method, we’ll end up with a list containing a “null” item, which can cause quite a few issues when managing the list.

immagine
immagine

"ClassicList": [
        "a",
        null,
        "c"
      ]

Now that we have some background on how a list works and the issues it presents, let’s move on to the actual solution to this problem:

using a dictionary with unique keys

I’ll start by saying that I always try to use native components, but in this case, I’ll make an exception since we’ll need RecyclerList, which I consider essential for any professional app.

Thank you :raising_hands: zainulhassan :raising_hands: for this amazing extension.

But let’s get straight to the practical part.


Layout


In this layout, I’ve included many non-essential components just for testing purposes.
What we’ll actually need is:

  • VerticalArrangement to contain the RecyclerView list
  • Web component to communicate with Firebase
  • RecyclerList

Then, of course, some components like Textboxes and Buttons to add items but that really depends on how you want users to input the data.

Blocks

Variables

6 variables, 3 required and 3 optional:

  • schemaFBListItem: contains the JSON template of the item for the RecyclerList
  • dbURL: the URL of the Firebase database
  • projectBucket: the Firebase project bucket
  • pendingValue: simply a variable used to store the value pending deletion/insertion
  • lastWebFunction: used to keep track of which Web function we’re executing (deletion/insertion)
  • dictionaryList: the dictionary containing our “list” of items

I’ll skip the RecyclerList initialization and creation part since there are already plenty of guides on that.
In short, it will create a schemaFBListItem template for each dictionary item
Assigning two unique keys, one linked to a CardView (CV_FBListItem_Item) to check if the user clicked on the item, and another CardView (CV_FBListItem_Delete) for deletion.
Finally, it sets the Label (Label_FBListItem_Item) with the item’s name.

immagine

Schema
{
	"name": "schemaFBListItem",
	"metadata-version": 1,
	"author": "",
	"platforms": [
		"creator.kodular.io"
	],
	"generator": "schema-generator",
	"extensions": {},
	"keys": [],
	"components": [
		{
			"id": "CV_FBListItem",
			"type": "MakeroidCardView",
			"properties": {
				"ContentPaddingBottom": 0,
				"ContentPaddingLeft": 0,
				"ContentPaddingRight": 0,
				"ContentPaddingTop": 0,
				"CornerRadius": 10,
				"Height": -1010,
				"Width": -2
			},
			"components": [
				{
					"id": "HA_FBListItem",
					"type": "HorizontalArrangement",
					"properties": {
						"AlignVertical": 2,
						"Height": -2,
						"Width": -2
					},
					"components": [
						{
							"id": "CV_FBListItem_Item",
							"type": "MakeroidCardView",
							"properties": {
								"AlignVertical": 2,
								"ContentPaddingBottom": 0,
								"ContentPaddingLeft": 0,
								"ContentPaddingRight": 0,
								"ContentPaddingTop": 0,
								"CornerRadius": 0,
								"Elevation": 0,
								"FullClickable": true,
								"Height": -2,
								"Width": -2
							},
							"components": [
								{
									"id": "Label_FBListItem_Item",
									"type": "Label",
									"properties": {
										"HTMLFormat": true,
										"HasMargins": false,
										"Width": -2,
										"Text": "Item",
										"TextAlignment": 1
									}
								}
							]
						},
						{
							"id": "CV_FBListItem_Delete",
							"type": "MakeroidCardView",
							"properties": {
								"AlignVertical": 2,
								"BackgroundColor": -769226,
								"ContentPaddingBottom": 4,
								"ContentPaddingLeft": 4,
								"ContentPaddingRight": 4,
								"ContentPaddingTop": 4,
								"CornerRadius": 50,
								"Elevation": 0,
								"FullClickable": true
							},
							"components": [
								{
									"id": "Label_FBListItem_Delete",
									"type": "Label",
									"properties": {
										"Clickable": true,
										"FontSize": 20,
										"FontTypeface": 7,
										"Text": "delete",
										"TextColor": -1
									}
								}
							]
						}
					]
				}
			]
		}
	]
}

firebaseGetValue

a simple get to retrieve the “list”

firebaseInsertUniquePair

This function will insert a key-value pair into a specific tag.

  • We disable the button that triggers the function so the user has to wait for the response before adding another value.
  • We set pendingValue to the item parameter passed to the function, here’s why:
    After sending an item to Firebase, we’ll receive a response containing the automatically generated unique key.
    This way, as soon as we get the response, we can associate that unique key with the pendingValue variable.
  • We then set the lastWebFunction variable to “insertUniquePair”
  • And perform a POST of the item.

firebaseRemoveUniquePair

This function, on the other hand, will delete a pair by specifying its key.

Here too, we’ll make use of pendingValue and set lastWebFunction to “removeUniquePair”, then perform a Delete method on tag/key.

Web.GotText

Here we’ll check the responses received from our functions.

  • If responseCode = 200 (success)
    • we verify that the response is not "null"
      • format it, and store it in formattedResponse
      • If the last function we used is getValue
        • we set our dictionaryList variable to formattedResponse
        • and tell the RecyclerList to generate the list using this data
      • If instead the function is insertUniquePair
        • we save the pair in our dictionary
        • notify the RecyclerList that an item has been added,
        • and display a Snackbar confirming the insertion.
    • If the response is "null" (we receive null when a pair is deleted),
      • and the last function = removeUniquePair
      • we tell the RecyclerList that the item at the position corresponding to pendingValue has been removed
      • We then remove the pair from our dictionary
      • and display a Snackbar
  • If the response code is not 200,
    • we show an error message.

And finally, we clear our variables and re-enable the button for adding new items.

There are other blocks, such as AnyCardView.Click, which checks whether we clicked on the item or the trash icon and calls the appropriate function, as well as the various buttons for GetValue and InsertUniquePair but they’re really very basic, so I won’t go into detail.

Done :partying_face:

Result

AIA

FirebaseList.aia (133.1 KB)

It was much harder to explain than to do! :grin:
As always, if there are any questions, I’m available for clarification.

Happy :kodular:oding!

3 Likes

Great Effort made, Nice Guide mate!

1 Like