JAMES DANIELS: Hey there, everybody.
Thanks for tuning in today.
I'm James Daniels, an engineer on the Firebase team.
I am joined by Minko, a colleague on the Angular team.
MINKO GECHEV: Hello, everyone.
My name is Minko Gechev.
I'm a developer programs engineer
on the Angular team at Google.
Today, we're going to develop an application
with Angular and Firebase.
In general, we're going to build a Kanban board
with different tasks that we can move
across three different states.
We can move them from a backlog to in progress,
and finally to completed.
JAMES DANIELS: Now, before we jump in,
let's talk a little bit about the technologies we're using
and the tools that can make your job easier.
First and foremost, we're building a web application.
So we need a place to host it.
That's where the aptly named Firebase Hosting comes in.
Firebase Hosting is a great product
for storing static web assets.
It puts everything behind a CDN, provides us
with an SSL certificate, and we can even
point our own domain at it once we're
ready to go live to the world.
Next, we need a database.
This is where Firestore comes in.
Cloud Firestore is a highly scalable NoSQL database
that has client-side SDKs, allowing us to write directly
from our web application code, securely, without the need
to spin up API servers.
Further, the SDK itself allows you
to keep your client state in sync with the server,
using real-time listeners.
This significantly cuts down on the complexity of building
a modern reactive interface.
Now let's spend a moment on tooling.
We have a few options that will influence our choices.
The Firebase CLI is an npm module
that gives us the ability to push files
to Firebase Hosting, deploy Cloud Functions, security
rules, and more, via an easy-to-use command line
interface.
This is how many of our developers
choose to interact with the hosting products.
Next, there are web development frameworks
that provide their own CLI experience,
and have hooks that allow developers
to integrate with them.
Notable examples here include Angular and Ember.js,
whose CLIs can become Firebase-aware using SDKs built
by the Firebase team.
The emberfire library, for instance,
makes a connection between the Firebase CLI and Ember,
allowing developers to build and deploy their app with a tooling
that they're already familiar with.
Next, we have the Firebase Hosting API,
a REST API that enables programmatic deployments
to Firebase Hosting.
While admittedly a bit more manual,
it gives you complete control over your release pipeline,
and can be consumed in environments
that aren't running Node.js, or don't have existing command
line interfaces.
There's some great integrations here, too.
Glitch and StackBlitz, for instance,
both have deploy to Firebase capabilities
built on top of this API.
That's the high level on the tooling options available to us
right now.
Perhaps there's an integration you'd like to see,
but doesn't exist today, whether it be your favorite
build tool chain, editor, continuous deployment pipeline.
And hey, maybe you'll be the one to build it.
Now that we've talked a bit about the technology
choices available to us here, I'm
eager to start building our app.
Let's jump over to Minko, who'll get us going.
MINKO GECHEV: So with Angular and Firebase,
we're going to build this Kanban board.
First, we're going to create a new Angular CLI project.
For the purpose to build the actual user
interface of the app, we're going
to add Angular Material and the Angular CDK.
Right after that, we're going to develop our application's
features.
And finally, we're going to just add the AngularFire package
to our Angular CLI workspace, so that we
can introduce some real-time capabilities
and deploy our application to Firebase Hosting.
First things first.
Let's create a new Angular CLI workspace.
For purpose, use the ng new command,
specifying a project name.
We'll not need the Angular router,
and here we're going to use just CSS.
This command will scaffold the project
and install all of its dependencies.
As a next step, let us add Angular Material.
Installing the package with npm will not do the entire trick,
so we're going to use the ng add command instead.
It will not only install Angular Material,
but also trigger the ng add schematics,
which will integrate the module with our application,
first by allowing us to select a theme
and adding the associated styles to the project.
It will also add a global Material typography,
and import the browser module in the app module.
And all of this is going to happen just automagically.
Notice that the ng add command added to the Angular CDK
to package.json as well, since it is a dependency
of Angular Material.
Now, let us quickly develop the layout of the application.
We'll first open the app.component.html
and delete its entire content.
At the top of the template, we'll
need to add a mat-toolbar.
Inside the toolbar, let us add a local_fire_department icon,
and next to it set the title of the app, which is KanbanFire.
When we go back to the console, run ng serve,
and well, here we're going to see just a bunch of errors.
This happened because we forgot to import the components
that we're actually using from Angular
Material in our application.
Now let us do that.
We'll first import MatToolbar module
from the angular/material/toolbar
module.
Next, we will add it to the list of imports in app module.
We will do the exact same thing for MatIconModule.
Finally, let us set the color of the toolbar
to the primary color of our theme.
We can now preview what we just did.
As a next step, let us add three columns,
or swim lanes, representing the different states a task could
be in.
In the templates of the app.component,
we'll create a column for the backlog.
The backlog will be a Material card, and inside of it,
we're going to show the individual items
from our to-do array by using the ngFor directive.
We will do the exact same thing for the progress and the done
columns.
We should now improve the layout of the application.
First, we'll wrap the column in a container wrapper,
and next, we will add a list class
to the individual columns.
Finally, just add item class to the cards
showing the individual tasks.
In the styles of the app.component,
we'll use flexbox in the container wrapper,
and set its margin top to 20 pixels.
Each column will have 400-pixel width, margin right 25 pixels,
and a solid gray border with 1-pixel width.
And of course, a minimum height of 60 pixels.
Yep, that just looks fine now.
Items will have margin bottom 10 pixels, a cursor pointer,
and box-sizing border box, to make sure
that their sizes do not change when we start
writing the individual tasks.
Oh, see, now we're getting another set of errors
in the console, because we are missing an import.
Let us quickly add the MatCardModule
to the app.module.
We also need to declare to do, in progress,
and done already in the app.component.
Let us also add a few items to to-do array.
And here we are.
Now we see three lists, and we have
items in the first one of them.
To implement the drag-and-drop functionality,
all we need to do is just to use a couple of directives
from the drag-drop module in the Angular CDK.
Let us import it in the app.module.
After that, we'll need to update the cards representing
the individual columns.
First, add cdkDrag to the mat-card representing the task.
And to each one of the columns, we'll
add the cdkDropList directive.
After that, we'll handle the cdkDropListDropped event
by invoking the drop method passing the event object.
Next, we'll set the cdkDropListData
to the corresponding array from the app.component.
And now, let us format the template with Prettier.
After that, we'll reference each DropList
using a template variable.
We'll use backlogList for the list of to-do items,
inProgressList for the list of in-progress tasks,
and doneList for the list of completed tasks.
Finally, we'll connect each DropList with the other two,
so that we can transfer tasks between them.
Let us implement the drop method in the app.component.
The event object is of type cdkDragDrop.
It contains the previous and the current containers.
We'll need to handle two cases here, reordering tasks
in the current column, and moving
tasks across different columns.
If the user is reordering tasks, we'll
use the moveItemInArray function coming from the CDK,
passing the container data, previous index,
and the current index.
Alternatively, we want to use the transferArrayItem
by passing the data from the previous container, the data
from the current container, the previous index,
and the current index of the task.
Now, let us try the drag-and-drop functionality.
Notice that there is a weird effect here.
When we start dragging a particular item,
we temporarily create a clone of it.
To fix this, we'll need to go to the app.component CSS
and declare it a class cdk-drag-placeholder.
Angular will apply it to the placeholder
when we start dragging.
To hide it, we'll just set its opacity to 0.
To improve the drop effect, we'll
just add 250 milliseconds transition
to the cdk-drag-animating class.
The only missing feature now, before we
go to the Firebase portion of this talk,
is to implement the functionality
for adding new tasks.
For the purpose, let us just wrap the container wrapper
into another div element, which will contain
all the three different columns, plus form for adding new tasks.
Let us use the content wrapper class for the [INAUDIBLE]
and add a few styles for it.
In the app.component CSS, make its width 1,000 pixels,
and set its margin to auto, so that we can center it.
In the app.component template, add a mat-form-field,
a mat-label inside of it with the value "Task name,"
and an input with the mat-input directive on it,
which handles enter keydown events, just
invoking the addItem method.
Don't forget to import mat-input module in your app.module
to make sure that we have all the directives available.
Inside the addItem method in the app.components controller,
we just want to get the target HTMLInputElement,
push its value to the to-do lists, and reset it.
Now we can add new items to our to-do list.
So that was pretty much everything on the Angular side.
Now James can show you how to add Firestore, and deploy
the application to Firebase Hosting.
JAMES DANIELS: Thanks for getting us rolling, Minko.
Well, to get Firebase in here, the first thing
that we're going to want to do is add the AngularFire library.
So we'll just do ng add AngularFire.
This will actually install the Firebase packages,
Firebase Tools, everything that we
need to put in real-time capabilities
and deploy to Firebase hosting.
So I'll link this to the project that I created for this.
Now that we've added AngularFire, let's pull
in the modules we need.
We'll first start with AngularFire,
and then we'll pull in the AngularFireStore module.
We'll initialize AngularFire with our application's webapp
settings.
You can get those from the Firebase console.
Next, in our app.component, let's actually
inject AngularFireStore.
Then we can convert our task list to a Firestore collection.
So we'll go ahead and get the collection todo.
Then we'll grab the valueChanges from that.
What that'll do is actually create an RxJS observable
of the values in Firestore.
And this will be a real-time connection.
ID field, we'll go ahead and populate the item's ID
into the task.
We'll do the same for inProgress and done.
Now with that, let's go ahead and work on our new task.
So instead of pushing to an array,
we're actually going to grab our Firestore collection,
and we're going to add to it.
Now edit.
So here, when we're deleting, we're
actually going to want to, again, jump into that Firestore
collection, grab the document ID, and then delete it.
Otherwise, let's update it.
And then we can get rid of all this.
Finally, the drag-and-drop.
So here, we're actually going to want to do a transaction.
This works in two pieces.
So we'll go ahead and create a Firestore transaction.
That'll take a Promise.
And in the Promise, we're first going
to delete the item from the prior collection,
and then we're going to add it to the next collection.
Now finally, our data is actually observables now,
so we're going to want to change our template code a bit.
So we're going to want to point our cdkDropListData
to the async.
We're going to want to update that for the empty list check
as well as the ngFor.
With that done, let's bring it up in the browser.
We can do side-by-side here, now that we're
persisting in Firestore.
I'm happy with this.
So I'm going to go ahead and deploy it to Firebase Hosting.
I can just call ng deploy, since we added AngularFire.
This will actually use a schematic,
reach into Firebase Tools, and build and deploy
our site on Hosting for us in one simple step.
And we're live!
MINKO GECHEV: If you're building tools for developers,
or just frameworks, and you want to enable
such path for your favorite framework,
just like what we showed today with the Angular
CLI and the Firebase schematics, just take a look at them.
They're at github.com/angular/angularfire.
You can develop similar mechanics
for your favorite technology so that you can enable developers
to add real-time capabilities with Firestore
and automated deployments to Firebase Hosting.
JAMES DANIELS: Thanks for joining us today.
We were happy to demonstrate some
of the new capabilities of Firebase Hosting,
and our integration with the Angular CLI.
If you'd like to dive a bit deeper in today's exercise,
be sure to catch the codelab that Minko
has developed for this summit.
Links to this and more can be found in the description below.
If you liked this video, be sure to subscribe to the Firebase
channel.
And make sure to catch the other great talks coming out
of the Firebase summit.
MINKO GECHEV: Thank you for watching, and happy coding.
See you next time.
[MUSIC PLAYING]