You have unlimited access as a PRO member
You are receiving a free preview of 3 lessons
Your free preview as expired - please upgrade to PRO
Contents
Recent Posts
- Object Oriented Programming With TypeScript
- Angular Elements Advanced Techniques
- TypeScript - the Basics
- The Real State of JavaScript 2018
- Cloud Scheduler for Firebase Functions
- Testing Firestore Security Rules With the Emulator
- How to Use Git and Github
- Infinite Virtual Scroll With the Angular CDK
- Build a Group Chat With Firestore
- Async Await Pro Tips
Build a Star Review System With Firestore
Episode 57 written by Jeff DelaneyIn this lesson, I am going to show you how to build a five-star rating system from scratch with Angular and Firebase.
Knowing how to implement star reviews in Angular is an important skill for a developer because the same concepts are used for likes, hearts, votes, and many other common UX features.
Firestore Data Structure
How do we model star-ratings in a NoSQL database like firestore? In the SQL world, this is known as a many-to
-many-through` relationship where Users have many Movies through Reviews AND Movies have many Users through Reviews
Firestore is a document database that is optimized for LARGE collections and SMALL documents.
In the diagram above, we can see how the movies collection and users collection have a two-way connection through the stars middle-man collection. All data about a relationship is kept in the star document - data never needs to change on the connected user/movie documents directly.
Having a root collection structure allows us to query both “Movie reviews” and “User reviews” independently. This would not be possible if stars were nested as a sub collection.
Initial Setup
I am going to focus on the middle-man star collection because that is were all the magic happens. You can set up a similar data relationship between any two collections - users and movies could just as easily be rainbows and unicorns. If your app still needs a user auth system with firestore, please follow firestore OAuth lesson to get up and running quickly.
Our final product will look like this:
App Component
For this demonstration, I am going to manually create a few user
documents and a movie
document. As you will see, the StarService
is completely independent, so you can easily drop it into your app. All you need is a reference to the two AngularFirestoreDocument
objects that you want to connect.
Here’s what the database collections and documents look like in Firestore.
In the app component, we will make a reference to the current user and movie. In the real world, you would get your user from an auth service. Movies might come from a URL param or a collection of movies. These issues are not directly relevant to our star feature, so I am simply hard coding them in the app component.
I also created a couple of getters to retrieve the document ID from the AngularFirestoreDocument
.
import { Component, OnInit } from '@angular/core'; |
The typescript getters will allow us to conveniently pass the document ids to a child component, which we are going to build later in the lesson.
<star-review [movieId]="movieId" [userId]="userId"></star-review> |
The Star Service
ng g service star --module app |
The star service will handle interaction with the stars collection in the Firestore back-end database.
- Get reviews by User
- Get reviews by Movie
- Set/update a review relationship
import { Injectable } from '@angular/core'; |
The StarReview Component
ng g component star-review |
You can drop the star review component into any other component that has access to a movie reference. It acts as a child component that will display/update reviews for its parent component - in this case movies.
The star review component will perform the following tasks.
- Show the average star rating
- List other users star ratings
- Allow user so set their own rating
The star service only requires a userId
and movieId
, therefore we can pass these values from the parent component using the @Input
decorator.
import { Component, OnInit, Input } from '@angular/core'; |
In the HTML, we can easily unwrap the average rating Observable with the async pipe. Then we can also loop over the stars observable to show ratings from other users.
To implement the clickable star buttons, we need to style radio buttons as star icons. In this case, we have 10 clickable radio buttons ranging from 0.5 to 5 stars. When clicked buy the user, it will trigger the starHandler(val)
method and update the corresponding data in Firestore.
Rather than code 10 different inputs, I loop over 5 integers and wrap the full-star and half-star in an ng-container
- that reduces the HTML code by ~80%.
Note: It’s important that the the id
on the input matches the for
property on the label.
<h3>Average Rating</h3> |
Lastly, I wanted to include the CSS that makes the star UI possible.
I borrowed the CSS for my stars from this CodePen, but the HTML has been modified for use in Angular. The CSS depends on FontAwesome icons, so make sure to include them in your project if using this code.
fieldset, label { margin: 0; padding: 0; } |
The End
Congrats, you now have a solid foundation for modeling user data relationships in Firestore. Please reach out if you have any questions.