Goals:
Right now, we have a todo-list app that works -- we can add items and we can even remove them! However, if you ever have to close your browser or reload the page, you'll lose everything on your list! Databases can fix that!
The topic we're discussing is called "Persistent State." Basically, data can either be persistent or not. Right now, our data is NOT persistent because it does not live on after our page reloads. We want to make our data persistent and to do so, we need to store it in a database which will save your data between sessions.
So what is a database? Well the name kind of speaks for itself: A database is a structured set of data held in a computer OR a place to store data!
So how do these things work? Right now, we know that variables store information -- is that the same thing? Nope.
Databases store data in a structured way. For Firestore, the data is structured into Collections and Documents.
A document is a single unit of storage. So if you wanted to store information about a user -- like a username, a First and Last name, and a password -- you'd store all of that info in a single document.
A collection is just a list of documents. So we could have a collection called "Users" inside of which we store all our documents that have specific data for each user.
For our app, we have Notes and our notes have text associated with them. As such, we'll have a collection called "Notes." Inside of that, we'll create a single document for every sticky-note where we'll save the text associated with the sticky-note.
Let's use our "User" example for this. So we want to add a user -- here's the Javascript code that would do it.
db.collection("users").add({
username: "arman22",
firstname: "Arman",
lastname: "Hezarkhani",
password: "armanrocks",
})
.then(function(docRef) {
console.log("You created a document! Here's its unique ID: ", docRef.id);
})
That's it! What just happened?
On the first line, we're declaring that we want to create
a new document inside of the "users" collection.
On lines 2-5, we're declaring the values that should be
saved inside of this new document.
On line 7, we have a .then()
statement. What's that? Let's take a step back.
Lines 1-6 are saving data to our Firestore database. To do
that, we're literally sending that data over the internet to
our database, then our database has to go through the
trouble of saving it, all of which takes time. As such,
we have a .then()
statement
to say the following: First, I want to store this data
to our database. THEN, once it's done, I want to run this
function.
So what's line 7 doing? It's telling our code what to do
after the database is done saving our data!
On line 8, we're simply printing out what the database
returned to us, which is an ID for this document.
Hint, Hint: It's a unique ID, JUST for this document.
We'll be using that later on!
Imagine we've saved a bunch of users. Now, we want to get every user and simply log the first and last names to the console.
db.collection("users").get().then((querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log("First Name: " + doc.data().firstname);
console.log("Last Name: " + doc.data().lastname);
});
});
This is also a bunch of new stuff -- so what's going on?
On line 1, we're saying: Hey Database, in that collection
called "users," get me every value and save that data inside of
'querySnapshot.'You don't have to know exactly what
'querySnapshot' is or means -- just know that it has the values
that we asked our database for.
On line 2, we're basically saying: Thanks for
sending me every doc I asked for. Now, for each document
that you sent me in querySnapshot, I'm going to do some stuff.
Lines 3 and 4 are just logging specific information from each
document.
I emailed you with a free cloud credit. Click on "Student Coupon Retrieval Link" and fill out the form. It'll then ask you to verify your email. Once you do, you'll receive another email with a Coupon, looking something like "XXXX-XXXX-XXXX-XXXX." That coupon holds $50 of free Google Cloud Credit.
Now that you've done this, you should be on the Firebase
"Getting Started" homepage. On there, you should see four
icons -- click on the third one, which looks like HTML code,
indicating a "Web" project.
This'll open up a new page to "Add Firestore to your Webapp."
Under Register App, put "todo_list" for the app nickname and
click "Register App."
Now, you'll see something like this:
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
Copy that somewhere (in an empty file somewhere), as we'll
need it in a moment.
AAAAAAAND that's all the set-up you need to do!!! Let's recap:
Now that we have our database set up, let's code!
Start by downloading the starter-code here here
Right now, the javascript simply runs some code when a form is submitted.
Let's add to that!
First, we'll need to add some configuration code -- this is
basically code that's required by Firestore in order for
the code to work.
At the top of the index.js
, add the following
code:
firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: ""
};
firebase.initializeApp(firebaseConfig);
var db = firebase.firestore();
Look familiar? Good! Make sure that firebaseConfig
has the values that you copied from earlier.
Now that we have the configuration, let's outline what we'll be doing in this code, every time our user submits a new Todo item:
In the previous lab, we did steps 1 and 3. Now, though, we'll
be saving to the database before we add a sticky-note
to the page.
Add some code to read the user's input and pass it to a
function called saveItemToDatabase
.
That should look something like this:
$("#form1").submit(function(e) {
e.preventDefault();
var todo_input = document.getElementById("todo-input");
var todo_text = todo_input.value;
saveItemToDatabase(todo_text);
todo_input.value = "";
});
function saveItemToDatabase(todo_text){
// Your Code Here!
}
So now, every time a user types a todo item, we pass the user's
input -- the todo_text -- to a function. In that function,
we want to save the todo_text to our firestore database.function saveItemToDatabase(todo_text){
// Save element to database
doc = db.collection("notes").add({
noteText: todo_text
})
}
So...what is this code doing? It's creating a Firestore Document
with one element -- noteText
-- and it's adding that
Document to the Collection called "notes"
.
Okay, now we're saving elements to our database, so we're
done with steps 1 and 2. Step 3 is to add our element to
a page -- lets add a .then()
statement to do that now!
After doing so, your code should look something like this:
function saveItemToDatabase(todo_text){
// Save element to database
doc = db.collection("notes").add({
noteText: todo_text
})
.then(function(docRef){
docRef.get().then(function(doc) {
addNewItem(doc);
});
});
}
function addNewItem(doc){
// Create new todo div to store all todo content
var todo_card = document.createElement("div");
todo_card.classList.add("todo_card");
// Put the todo item in a p
var todo_text_elem = document.createElement("p");
todo_text_elem.innerHTML = doc.data().noteText;
// Construct the entire element
todo_card.appendChild(todo_text_elem)
// Add it to the DOM
document.getElementById("container").appendChild(todo_card);
}
Now, every time a user submits a todo item, we're saving the
text to the database. When that save is complete, we're passing
the document object that the database returns to our
addNewItem
function to add
the text to the page.
Now, let's write some code to delete the sticky-notes!
First, we'll need to give the sticky-notes a unique ID.
Luckily, Firebase automatically generates a unique ID for
every document you create, and it's stored inside of
doc.id
.
So, the following code should allow us to give our sticky note
a unique ID:
var todo_card_id = doc.id
todo_card.id = todo_card_id
Lastly, we can add the following code to remove the element
from the page AND delete it from the database:// Add a click listener to the todo card
todo_card.addEventListener("click", function(){
// Remove Element from the DOM
document.getElementById(todo_card_id).remove()
// Delete from Database
db.collection("notes").doc(doc.id).delete();
});
Yay!!! Now, we can delete items, too!
There's an issue, though... Try refreshing the page :(
This is happening because we're not loading elements from
the database when we first load the page.
If you add the following code to the bottom of the javascript document,
that'll work, too:
function loadNotes(){
db.collection("notes").get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
addNewItem(doc);
});
});
};
$(document).ready(function(){
loadNotes()
});