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
Reddit Style Upvoting in Angular 4 and Firebase NoSQL
Episode 13 written by Jeff DelaneyUpvoting and downvoting is an excellent ay handle community-driven content curation. Reddit is the most famous example of this feature, but it is common throughout the interwebs on places like StackOverflow, Kaggle, and others. In this lesson, we will use Angular 4 and Firebase to implement upvoting with ease.
Prerequisites
You need to have user authentication wired up. You also need some other resource in the database that can upvoted, such posts, comments, items, etc. Check out these lessons if you get lost.
Modeling the Voting Data in NoSQL
Our database needs to answer two questions as efficiently as possible. (1) Did this user vote for an item? (2) How many people voted on an item?
We can answer these questions by creating a collection of itemIds (using the firebase $key for items), with each document containing key-value pairs of userIDs (auth uid). The key is the userId and the value is their vote, which can be +1, 0, or –1.
-| upvotes |
To answer the first question, we can query the table with the itemId, then see if there is an existing userId key and vote value. We answer the second question by counting get the sum of the vote values.
Upvote Service
We will use a service to query Firebase for the upvote data. First, we need a function to get the document for a specific item as a FirebaseObjectObservable
. Next, we need to update the document when the user casts a vote. Here we sent the object key equal to the userId, then update the document with vote value.
upvote.service.ts
import { Injectable } from '@angular/core'; |
Upvote Component TypeScript
An example of the upvote feature UI with Firebase updating in realtime
Most of the work will happen in the component. First, we are passing the component an itemId and userId via the @Input()
decorator. Again, check out the prerequisites if you’re app still needs authentication. It should look like this:
<upvote-button [itemId]='item?.$key' [userId]='user?.uid'></upvote-button> |
Here’s how the component works step-by-step.
1 The input values are passed from the parent component, then used to interact with the service. We also set variables that will hold the user’s current vote and the total vote count for an item.
2 After injecting the service, we use the getItemVotes()
function and subscribe to the observable that it returns. The emitted value is a document of userIds and vote values from the database. If a userID is present, we check for the matching userId to see if a vote has cast.
Lodash is used to calculate the total vote count. The values
function converts the object values into an array, then sum
does exactly what you would expect. Much cleaner than plain JavaScript!
4 Now we need functions to let the user upvote and downvote. Each of these functions are identical - only the vote value is different, +1 for up and –1 for down. To facilitate the cancellation of votes, a ternary if operator is used to determine a value. It reads like this. “If you already upvoted, then I set your vote to 0, otherwise I set it to 1”.
Lastly, don’t forget to destroy the subscription. If your app has a large amount of content, this feature could definitely introduce memory leaks.
upvote-button.component.ts
import { Component, OnInit, Input, OnDestroy } from '@angular/core'; |
Upvote Component HTML Template
When the user clicks an arrow, their vote is cast by calling either the upvote or downvote function. The ngClass
directive is used to apply an active class when the user vote is valued at 1 or –1. In this case, an upvote is colored green and a downvote is red.
upvote-button.component.html
<div class="votebox"> |
The Component SCSS
And let’s finish this off with some CSS. FontAwesome was used for the arrow icons, BTW.
.votebox { |
Thats’s it for Reddit voting. Good luck!