Angular & Firebase for Fast, Easy Database Apps

Photo by Campaign Creators on Unsplash

I recently started working on a new personal project that needed a database, and I just wanted something quick & easy. I remembered a colleague mentioning Firebase in the past and decided to take a look. After playing with it for a few days, I really dig it. I love that you can set up a database for free within a few minutes, and access it directly from the frontend without having to introduce a separate API layer.

In this article, I’ll walk through steps required to create a new Angular application and connect it to a Firebase Cloudstore database. You’ll need to sign up with Firebase to create the database, but it’s free and painless. Let’s get to it!

We’ll begin by creating a new application using the Angular CLI:

$ ng new firebase-app
$ cd firebase-app

Next, we’ll create our Firebase Cloudstore database. Go to firebase.com, and create an account or sign in. Add a new project and Cloudstore database in test mode. Finally, add a web app to the project. When you do this, you’ll be presented with instructions for adding the Firebase SDK to your app, as shown below.


Copy/paste the configuration details into our applicaton’s app.module.ts file. (Don’t worry about putting it in the right spot–we’ll do that in a minute. Just get it in there so you have it.) Now it’s time to install the Firebase and the Angular Firebase module:

$ npm -i firebase @angular/fire

When you install @angular/fire a browser will open for you to authenticate with Firebase, and you’ll be given an authorization code. Copy/paste the code back to the command prompt to finish installing the module.

With the module installed, we complete the necessary changes in app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AngularFireModule } from '@angular/fire';
import { AngularFirestoreModule } from '@angular/fire/firestore'

import { AppComponent } from './app.component';
import { DemoComponent } from './demo/demo.component';

// Your web app's Firebase configuration
var firebaseConfig = {
  apiKey: "AIzaSyAx2cAfq9Pj3EzavXLkNc6_F9zWCyIayY4",
  authDomain: "ap-sample-1218e.firebaseapp.com",
  databaseURL: "https://ap-sample-1218e.firebaseio.com",
  projectId: "ap-sample-1218e",
  storageBucket: "ap-sample-1218e.appspot.com",
  messagingSenderId: "200601572991",
  appId: "1:200601572991:web:a335d1e106542870a9914a"
};
  
@NgModule({
  declarations: [
    AppComponent,
    DemoComponent
  ],
  imports: [
    BrowserModule,
    // Initialize Firebase
    AngularFireModule.initializeApp(firebaseConfig),
    AngularFirestoreModule,
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

At this point, we’re actually done with setup and fully functional, but let’s add a new component to demonstrate its usage:

$ ng g c demo

Open demo.component.ts, and add the following:

import { Component, OnInit } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-demo',
  templateUrl: './demo.component.html',
  styleUrls: ['./demo.component.css']
})
export class DemoComponent implements OnInit {

  items: Observable<any[]>;
  
  constructor(
    private firestore: AngularFirestore
  ) { 
    this.items = this.firestore.collection('items').valueChanges();
  }

  ngOnInit(): void { }

  saveItem(value: string): Promise<any> {
    return this.firestore.collection('items').add({
      value: value
    });
  }
}

Add some simple markup to add & display items in demo.component.html:

<input #input type="text">
<button (click)="saveItem(input.value)">Add</button>

<ul>
    <li *ngFor="let item of items | async">
        {{item.value}}
    </li>
</ul>

Finally, remove boilerplate code from app.component.html and replace it with the demo component:

<app-demo></app-demo>

Now run the app. When values are submitted, they’re saved to our Firebase Cloudstore database, and the page will update in realtime as new records are added. Not bad for a few minutes of work!

$ ng serve --open

Make a Trello Clone in 15 Minutes

In the past weeks, I’ve written about how to make a drag & drop list using Angular CDK and how to enable dragging & dropping between multiple lists. Trello is the app that first comes to mind when I think of how this can be used to create a great experience.

At its core, a Trello board has just three pieces of functionality: create lists, create cards within the lists, and reorganize cards within and between the lists. The articles above give us all the tools we need to do this quickly ourselves, so let’s do it!

We’ll use the Angular CLI to do the following:

  1. Create a new app
  2. Add a list component
  3. Add a board component
  4. Make it pretty

Create New App

This first step’s pretty easy. We’re just going to use ng to create a new app and install the Angular CDK.

$ ng new lists-app --defaults
$ cd lists-app
$ npm install @angular/cdk

Do a quick check to make sure we’re starting in a good state:

$ ng serve --open

Add List Component

Now we’ll make our list component using ng generate component.

$ ng g c list

Hop into the code and make three changes. First, we need to import the DragDrop and Forms modules in src/app/app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { FormsModule } from '@angular/forms';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ListComponent } from './list/list.component';

@NgModule({
  declarations: [
    AppComponent,
    ListComponent
  ],
  imports: [
    BrowserModule,
    DragDropModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Next, update src/app/list/list.component.ts to support drag/drop and dynamic creation of items. We’ll add the items array to store our list items, a drop function to handle our drop/drop event, and an onSubmit function to add new items to our list.

import { Component, OnInit } from '@angular/core';
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
import { NgForm } from '@angular/forms';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {

  items: string[] = [];

  constructor() { }

  ngOnInit(): void {
  }

  drop(event: CdkDragDrop<string[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(
        event.container.data,
        event.previousIndex,
        event.currentIndex);
    } else {
      transferArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex);
    }
  }

  onSubmit(newItemForm: NgForm) {
    this.items.push(newItemForm.value.newItem);
    newItemForm.reset();
  }
}

The third step is to change our markup in src/app/list/list.component.html. This is just two parts, displaying the drag-&-droppable list items and accepting input for new items.

<div cdkDropList [cdkDropListData]="items" (cdkDropListDropped)="drop($event)">
    <div *ngFor="let item of items" cdkDrag>{{item}}</div>
</div>
<form #newItemForm="ngForm" (ngSubmit)="onSubmit(newItemForm)">
    <input name="newItem" ngModel type="text" placeholder="Enter a new item"><button type="submit">Add Item</button>
</form>

That’s it for our list component, but let’s make one more change to app/app.component.html so we can test. Replace its entire contents with the following:

<app-list></app-list>

Now let’s do another check-in. We should be able to add items to our list and move them around via drag & drop.

$ ng serve --open

Add Board Component

Once again, we look to ng generate component to create our board component.

$ ng g c board

Just like the list component allows for dynamic creation of list items, we want our board component to allow dynamic creation of lists. So, let’s modify src/app/board/board.component.ts to support this:

import { Component, OnInit } from '@angular/core';
import { ListComponent } from '../list/list.component';

@Component({
  selector: 'app-board',
  templateUrl: './board.component.html',
  styleUrls: ['./board.component.css']
})
export class BoardComponent implements OnInit {

  lists: ListComponent[] = [];

  constructor() { }

  ngOnInit(): void {
  }

  addList() {
    var newList = new ListComponent();
    this.lists.push(newList);
  }
}

And make the markup changes in src/app/board/board.component.html. One thing to note is the use of cdkDropListGroup. This makes all the lists connected and allows dragging & dropping between them.

<button (click)="addList()">Add List</button>
<div class="list-container" cdkDropListGroup>
    <app-list *ngFor="let list of lists"></app-list>
</div>

We’ll also modify src/app/board/board.component.css so that lists will be added horizontally.

.list-container {
    display: flex;
    flex-direction: row;
}

Finally, we’ll update app.component.html to use our board component instead of a single list:

<app-board></app-board>

Our board component is complete, so let’s do another check-in.

$ ng serve --open

Make It Pretty

At this point, the hard part’s done. We have our core functionality implemented. We can add lists, add items to the lists, and move the items around. Now let’s make it look nice!

Begin by installing Angular Material:

$ ng add @angular/material

Then import the MatCard, MatButton, and MatInput modules in src/app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatInputModule } from '@angular/material/input';
import { NgModule } from '@angular/core';

import { AppComponent } from './app.component';
import { ListComponent } from './list/list.component';
import { BoardComponent } from './board/board.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

@NgModule({
  declarations: [
    AppComponent,
    ListComponent,
    BoardComponent
  ],
  imports: [
    BrowserModule,
    DragDropModule,
    FormsModule,
    BrowserAnimationsModule,
    MatButtonModule,
    MatCardModule,
    MatInputModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Now we can use mat-card, mat-raised-button, and mat-form-field in src/app/list/list.component.html:

<div class="container">
    <div class="list" cdkDropList [cdkDropListData]="items" (cdkDropListDropped)="drop($event)">
        <mat-card class="list-item" *ngFor="let item of items" cdkDrag>
            <mat-card-content>
                <p>{{item}}</p>
            </mat-card-content>
        </mat-card>
    </div>
    <form #newItemForm="ngForm" (ngSubmit)="onSubmit(newItemForm)">
        <mat-form-field>
            <input matInput name="newItem" ngModel type="text" placeholder="Enter a new item">
        </mat-form-field>
        <button mat-raised-button type="submit" color="accent">Add Item</button>
    </form>
</div>

And we’ll add a little CSS to src/app/list/list.component.css:

.container {
    margin-right: 10px;
}

.container button {
    margin-left: 5px;
}

.list {
    padding: 10px;
    max-width: 100%;
    border: solid 1px #ccc;
    min-height: 60px;
    display: block;
    background: #fafafa;
    border-radius: 4px;
    overflow: hidden;
}

.cdk-drag-preview {
    box-sizing: border-box;
    border-radius: 4px;
    box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
}

.cdk-drag-placeholder {
    opacity: 0;
}

.cdk-drag-animating {
    transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

.list-item {
    margin: 5px;
}

.list-item:last-child {
    border: none;
}

Then we’ll do some similar things to src/app/board/board.component.html and board.component.css:

<button (click)="addList()" mat-raised-button color="primary">Add List</button>
<div class="list-container" cdkDropListGroup>
    <app-list *ngFor="let list of lists"></app-list>
</div>
button {
    margin: 10px;
}

.list-container {
    display: flex;
    flex-direction: row;
    margin: 10px;
}

Now we’ve got fancy buttons, some input animations, and shadows while dragging, and it looks quite nice!

That’s where we’ll leave it today. The code I wrote while constructing this post can be found here.

Custom Background in Microsoft Teams

Microsoft Teams has had the ability to blur your background for a while, but they just expanded this to allow the use of a background image instead of just the blur effect. Out of the box, you’re only allowed to choose from a selection of Microsoft-provided images, but support for custom images is there–you just have to know where to drop your images.

So, here it is. Copy your images to the following directory, and they’ll show up in Microsoft Teams when you enable background effects:

%APPDATA%\Microsoft\Teams\Backgrounds\Uploads

If the Backgrounds\Uploads path doesn’t exist on your computer, it might be because you haven’t used the background effects feature yet. Turn on your camera, pick a background image, and the folder should get created. Or just go create it yourself.

Microsoft’s images use 1920×1080, so I recommend following suit for best results.

Upgrade to Ubuntu 20.04

Image by rockiger from Pixabay

The newest LTS version of Ubuntu is scheduled to release on April 23. Once it’s released, upgrading is as easy as running a few commands. In this article, we’ll walk through the process of updating the current system and then performing the upgrade.

Before you upgrade, make sure your system is as up to date as possible. Do this by running the follwing commands:

sudo apt update 
sudo apt upgrade
sudo apt dist-upgrade
sudo apt autoremove

Now that you’ve confirmed you’re up to date, it’s time to do the upgrade.

sudo apt install update-manager-core
sudo do-release-upgrade

If you receive a No new release found message, it means the upgrade hasn’t been made available to you. It’s been noted that the upgrade path from 19.10 will not be enabled until a few days after release, and the upgrade from 18.04 LTS will not be enabled until a few days after the 20.04.1 release expected in late July. However, you can force the upgrade at your own risk by using the -d flag.

sudo do-release-upgrade -d

Change Default Application For File Type Via Command Line

While I was setting up Windows Terminal, I found that trying to modify settings would open a new instance of Visual Studio since that was my system’s default application for .json files. That’s a pretty heavy choice for what amounts to a text editor, so I thought I’d change my default app to Visual Studio Code. Should be easy, right?

The usual way to do this is through Windows Settings:

Settings > Default Apps > Choose default apps by file type

The problem is, when I did that, Visual Studio Code wasn’t an option!

That’s okay, though. We can change the default app through the command prompt. Open a command prompt in Windows Terminal (note: Command Prompt, not PowerShell) and run the following:

assoc .json=jsonfile
ftype jsonfile="%AppData%\Local\Programs\Microsoft VS Code\Code.exe" "%1" %*

Solution credit, here.

Windows Terminal, For a Handsome Command Line Experience

A co-worker was giving a demo a few weeks back, and my key takeaway wasn’t what it should’ve been. I left with, “Why did their command prompt look so much better than mine!?”

Now, I’ve admittedly done zero customization with my command prompt. I’ve been using the plain blue default PowerShell prompt for as long as I can remember. I learned they were using the new Windows Terminal. I invested a little time in setting it up & customizing, and I feel super cool now.

Scott Hanselman has a great article on how to get it & make it look good, and that’s a great place to start.

My journey deviates from his a little, though, for unrelated reasons. First, my Windows Store doesn’t load. Not a problem, though, since you can also install it using Chocolatey.

$ choco install microsoft-windows-terminal 

You can follow Hanselman’s steps for installing posh-git:

$ Install-Module posh-git -Scope CurrentUser
$ Install-Module oh-my-posh -Scope CurrentUser

And for updating your profile (run notepad $PROFILE) to include the following. Note that I prefer the Sorin theme for Oh My Posh:

Import-Module posh-git
Import-Module oh-my-posh
Set-Theme Sorin

I also installed his suggested font, Cascadia Code PL, which can be obtained here.

My last step was to make a few more customizations via Windows Terminal’s profile settings (ctrl+, from Windows Terminal). I adjusted the color scheme, font size, and starting directory by adding the following:

"profiles":
{
    "defaults":
    {
        // Put settings here that you want to apply to all profiles
        "colorScheme": "One Half Dark",
        "fontFace":  "Cascadia Code PL",
        "fontSize": 10,
        "startingDirectory": "c:/source"
    },

Angular Drag & Drop Between Lists

Last week I shared steps to make a drag & drop application in Angular in just a few minutes. This is great for sorting items within a single list, but drag & drop is more exciting when used for interaction between elements. Today we’ll look at what it takes to extend last week’s project to include two lists that we can drag & drop between.

Code from the previous article is available here.

The first thing we’ll do is modify the todo-list component to have two lists. Modify todo-list-component.html to have a second cdkDropList element as shown in the code below. We also need to indicate that these lists are connected.

<h2>TODO</h2>
<div 
    cdkDropList 
    #todoList="cdkDropList"
    [cdkDropListData]="tasks"
    [cdkDropListConnectedTo]="[doneList]"
    class="example-list" 
    (cdkDropListDropped)="drop($event)">
    <div class="example-box" *ngFor="let task of tasks" cdkDrag>{{task}}</div>
</div>
<h2>COMPLETED</h2>
<div
    cdkDropList 
    #doneList="cdkDropList"
    [cdkDropListData]="completedTasks"
    [cdkDropListConnectedTo]="[todoList]"
    class="example-list" 
    (cdkDropListDropped)="drop($event)">
    <div class="example-box" *ngFor="let task of completedTasks" cdkDrag>{{task}}</div>
</div>

Now we need to make a pair of changes to todo-list.component.ts. First, we need to add the completedTasks collection referenced by our second list. We also need to modify the drop event handler to determine whether we’re rearranging a list or moving an item between lists.

import { Component, OnInit } from '@angular/core';
import {CdkDragDrop, moveItemInArray, transferArrayItem} from '@angular/cdk/drag-drop';

@Component({
  selector: 'app-todo-list',
  templateUrl: './todo-list.component.html',
  styleUrls: ['./todo-list.component.css']
})
export class TodoListComponent implements OnInit {
  tasks = [
    'Cleaning',
    'Gardening',
    'Shopping'
  ];
  completedTasks = [];

  constructor() { }

  ngOnInit(): void {
  }

  drop(event: CdkDragDrop<string[]>) {
    if (event.previousContainer === event.container) {
      moveItemInArray(
        event.container.data, 
        event.previousIndex, 
        event.currentIndex);
    } else {
      transferArrayItem(
        event.previousContainer.data,
        event.container.data,
        event.previousIndex,
        event.currentIndex);
    }
  }
}

That’s it–we’re done! Let’s run the application and see what happens.

$ ng serve --open

We can now rearrange items in the individual lists, as we could before, and move items between the two lists. Final code for this article is available on GitHub, here.

Feature image by Alexandra_Koch from Pixabay

%d bloggers like this: