After following along with the last lesson, our application should be able to retrieve Albums from Firebase, create new Album entries in our database, and even locate and retrieve specific entries based on their Firebase keys.

This lesson will further explore how we can manage Firebase databases directly through our applications. We'll add functionality to update Albums both in our application, and in our database. Along the way we'll also discuss how to re-use components in multiple places.

Updating Firebase Entries

Create a Component

Last week we detailed that components should have singular, dedicated jobs. Editing an Album in both our application and database is a distinct responsibility. Therefore, we'll make a dedicated component to manage it.

Next, we'll need to decide where to place the EditAlbumComponent. Our application currently includes a localhost:4200/admin route where new Albums can be created. Since editing Albums should also be an administrator-only capability, we'll place our EditAlbumComponent in the Admin route.

But the admin will need to select whichAlbum to edit. This means we must list all Albums in the Admin route, too. So an administrator may view all Albums at a glance, and select which they'd like to edit.

We could add code to list Albums to our AdminComponent. But we already have a component meant to display our list of Albums: TheMarketplaceComponent.

Reusing a Component

We'll reuse our MarketplaceComponent in the Admin route. This will both keep our project DRY, and provide an opportunity to practice reusing components.

To reuse a component, we just place its selector tags in a second location. The selector property of MarketplaceComponent is app-marketplace. So we'll place <app-marketplace></app-marketplace> tags in our AdminComponent template:

Simple as that, we can serve our application and see all Albums listed in the Admin route:

This is a great start; but there's a few things we could do to make this more user-friendly.

For instance, admins will likely want to see Albums' descriptions before deciding whether to edit them. They currently need to navigate to the detail page to view this information. Let's instead display allAlbum properties in the Admin route.

We also need to provide admins a form to edit Albums here in the Admin route.

But neither of these changes should appear in our localhost:4200/marketplace route. These changes should only be visible in the localhost:4200/admin route. Thankfully, there's an easy trick to hide and show content based on the user's current route.

Determining the Current Route

Any component with access to the router may call this.router.url to receive the current route's path.

Let's try this out. The MarketplaceComponent should already have access to our router. We'll print the current route to the console in its ngOnInit() method:

We'll also place an *ngIf directive in the MarketplaceComponent template. This directive will only render the EditAlbumComponent and display the Album's description if the user is located on the Admin route:

If we reload we should see that the MarketplaceComponent looks the same as before on the localhost:4200/marketplace route.

However, when this same component is rendered in the localhost:4200/admin route, it also displays the Album's description, and the "edit-album works!" filler text from the EditAlbumComponent template:

Note on Changing Component Appearance Between Routes

Before we move on, let's address an important best practice. As you can see, It's fairly easy to alter a component's appearance based on the current route. This allows us to easily reuse components between routes, keeping our code DRY.

However, while tweaking a component to reuse it in multiple locations is absolutely fine, largely altering its entire appearance or purpose is a telltale sign you should make a new component instead.

Two-Way Data Binding Form

Now that EditAlbumComponent is rendered in MarketplaceComponent while on our Admin route, we can begin adding code to actually update Albums. First we'll need an edit form:

We add [selectedAlbum]="album" to the existing <app-edit-album></app-edit-album> tags. This tells MarketplaceComponent to pass the current album from the directive loop to the EditAlbumComponent's @Input field named selectedAlbum.

We should now see an edit form next to each Album on the localhost:4200/admin route:

Updating Event Bindings

Unfortunately, if we click our edit form our application navigates to the Album' detail page! This is because the div where Album info resides has an event binding attached to it. The event binding runs goToDetailPage() when clicked, navigating to our Album Detail route:

We should now be able to edit Albums and see changes instantly reflected in the template! However, if we navigate back to localhost:4200/marketplace our changes are no longer present. This is because we're not saving the updated information to Firebase.

Saving Updates to Firebase

We'll need to save changes made in EditAlbumComponent to Firebase too. Because our AlbumService manages the application's relationship with Firebase, we'll also rely upon it to locate and update Album entries.

First, we'll inject AlbumService into the EditAlbumComponent. This will allow the component to invoke the service, and request it alter a database entry when the edit form is submitted:

updateAlbum() takes the local copy of the Album as an argument. Remember, this local version of Album has been edited with our two-way data binding edit form.

It calls the existing getAlbumById() method to locate the Firebase entry corresponding to this Album. We assign this Firebase entry to the variable albumEntryInFirebase.

getAlbumById() requires the Firebase-assigned $key as an argument. So we call localUpdatedAlbum.$key within the argument to getAlbumById().

After the database entry has been located, we call AngularFire's built in update() method on albumEntryInFirebase.

We update() the Album's new properties. These are formatted as key-value pairs. The key in each refers to the property in Firebase we're updating. The value of each contains the Album's local, updated properties.