Parent-Child Categories in Firebase and Ionic2

Image

Today I want to show you how I was able to add parent-child categories in my ionic2 app - MoneyLeash2 - with a Firebase backend; and a couple of hacks that allowed me to display the relationships on the page.

categories

This is the second post of the ionic2 weekly challenge series (#ionic2weeklychallenge) and for the purposes of this tutorial I’m assuming you already have ionic fully configured and running on your DEV environment and you’re familiar with Firebase.

First Thing’s First: Ionic Info

Check your local configuration against the dependencies below.

Dependency Version
Cordova CLI 6.5.0
Ionic Framework Version 2.0.0
Ionic CLI Version 2.2.1
Ionic App Lib Version 2.2.0
Ionic App Scripts Version 1.0.0
ios-deploy version Not installed
ios-sim version Not installed
OS Windows 10
Node Version v6.7.0
Xcode version Not installed

You will learn 2 Hacks to Display Categories on your App

  1. The first is how to structure your Firebase data
  2. The second is how to display parent-child categories on your app


Firebase Data Structure

I needed to meet 2 important criteria in my firebase data structure in order to have optimized reads and writes from my app.

  1. Categories needed to be logically grouped by relationships to avoid complex queries or loops. This was extremely important because Firebase, unlike relational database, has limited support for complex queries
  2. Categories needed to be sorted alpabetically on the page

This is the data structure I used for my app to save categories and relationships in Firebase. As you can see, it’s simple and straight forward. If you’re wondering how this simple data structure turns into the category display from the picture above, just wait. The secret sauce is coming.

categories
├── Expense
│   ├── -KZP705zZVdi9ARDjD4B
│   │   ├── categoryname: "Auto"
│   │   ├── categoryparent: ""
│   │   ├── categorysort: "Auto"
│   │   ├── categorytype: "Expense"
│   ├── -JxWSZJjuNfWeRPKPnJC
│   │   ├── categoryname: "Gas"
│   │   ├── categoryparent: "Auto"
│   │   ├── categorysort: "Auto:Gas"
│   │   ├── categorytype: "Expense"
  • categoryname: the name of the category to be displayed on the screen
  • categoryparent: the name of the parent category
  • categorysort: the sorting criteria applied to the Firebase query when pulling the data
  • categorytype: the type of category (expense / income)


How to display parent-child categories on your app

Here comes the fun part. I added a service provider to pull the data from Firebase. The constructor includes Firebase references to different data nodes in my database, as shown below

userData.ts

userdata;
housedata;
profilepicdata;
constructor(
    public af: AngularFire,
    public loadingCtrl: LoadingController) {
    this.userdata = firebase.database().ref('/users/');
    this.housedata = firebase.database().ref('/houses/');
    this.profilepicdata = firebase.storage().ref('/profilepics/');
  }

The getExpenseCategories function makes use of one of those references included in the constructor to pull the data from Firebase with a custom sorting on categorysort

getExpenseCategories() {
  return this.housedata.child(this.user.houseid + '/categories/Expense').orderByChild('categorysort');
}

This is Hack #1. I am joining the parent and child categories together as part of the categorysort node with a semi-colon in between - like in the example above categorysort: "Auto:Gas". This allows me to change the parent for any of the categories on list, and the categorysort node will allways be updated with the new selection allowing the sorting to work properly. The semi-colon doesn’t do anything at all. I could have used a different data delimiter.

Now to the Display Part

On the Category-List page, I call the service provider from the ionViewDidLoad() page event and load an expenseCategories array. This will return my Expense Categories sorted by categorysort

ionViewDidLoad() {

    this.userData.getExpenseCategories().on('value', (expensecategories) => {
      let rawList= [];
      expensecategories.forEach( spanshot => {
        var cat = spanshot.val();
        rawList.push({
          $key: spanshot.key,
          categoryname: cat.categoryname,
          categorytype: cat.categorytype,
          categoryparent: cat.categoryparent,
          categorysort: cat.categorysort
        });
      });
      this.expenseCategories = rawList;
    });

  }

The HTML template to display the categories is simple, as shown below:

<ion-item-sliding *ngFor="let expensecat of expenseCategories" #slidingItem track="expense" [ngClass]="{mlindent: expensecat.categoryparent !== ''}">
  <button ion-item (click)="edit(slidingItem, expensecat)">
    {{ expensecat.categoryname }}
  </button>
  </ion-item-options>
</ion-item-sliding>

And this is what it looks like on the page. Notice that there is no clear and visible distinction between parent and child categories

categories flat

And here’s Hack #2. I am adding a CSS class mlindent dynamically if the category contains a parent

[ngClass]="{mlindent: expensecat.categoryparent !== ''}"

And the end result is this:

categories

I get a parent-child category system in my ionic2 app with a Firebase backend with a simple and efficient approach!


Me

Luis Cabrera is a family man and a dedicated dad. He lives in Florida, where he works as an Applications Architect for one of the most recognizable brands in the US. In his spare time, Luis likes to develop apps using ionic and Firebase. Aside from technology and family, he enjoys the outdoors and working on his horse farm.

Older posts...

Written by

Get in touch!

Notice any mistakes?
Leave me a message