Posting & Displaying Posts

Now that we have users that can create posts, we can save posts that users write to the database and display those posts on the website.

We are going to use front-end JavaScript to post new content to the database and retrieve posts to display.

To do this we will create to separate files to handle each function: js/publish.js and js/posts.js.

Publish a post

We have already added the HTML elements a user can use to write a new post and click to publish it.

<div id="write-post"> <textarea id="post-body" placeholder="What's on your mind?"></textarea> <br> <button id="submit-post">Publish</button> </div>

We need references to the post textarea and Publish button, and an event listener for when the user click "Publish".

const publishButton = document.getElementById('publish-post'); const postInput = document.getElementById('post-text'); publishButton.addEventListener('click', publishPost); publishButton.addEventListener('keyup', function(event) { // user hits enter button if (event.which == 13) { publishPost(); } });

Finally, our publishPost function will get the user authentication info, find their part of the database and then grab the text from their post to publish. We'll also record the current date to save along with the post to display.

// reference to location of posts in database const ref = firebase.database().ref('posts'); function publishPost() { const post = {}; // object to store post information post.text = postInput.value; post.date = Date.now(); post.uid = firebase.auth().currentUser.uid; ref.push(post); postInput.value = ""; // reset post input }

ref.push adds a new entry to a field of the database.

A Promise could be assigned to make sure the post is successful and alert the user if it is not.

We will add some code to make the new post appear in the next section.

postInput.value = ""; simply clears the textarea so the user can write a new post.

Displaying posts

Once we can save posts, we want to display them. This is a separate function that will go in js/posts.js. This way we can keep processes separate to be more modular.

First we need to get a reference to the #posts div in the HTML to add the post content to. We'll also get a reference to the posts area of the database.

const posts = document.getElementById('posts'); const postRef = firebase.database().ref('posts');

Because we want to separate our user data and posts data, we need to load the users into the page before we can load there posts, to cross reference their user names, and later profile images.

/* get user data then load posts */ let userCount = 0; const users = {}; firebase.database().ref('users').on('child_added', function(snapshot) { users[snapshot.key] = snapshot.val().displayName; userCount++; }); firebase.database().ref('users').once('value', function(snapshot) { if (snapshot.numChildren() === userCount) { loadPosts(); } });

The postRef part of the database can be used to detect when new posts have been added. We're going to create two event listeners to listen for new content being added, using the "child_added" event. The convenient thing about this event is it will go through all of the existing children at the beginning and then continue listening for new children added.

function loadPosts() { postRef.on('child_added', function(snapshot) { createPost(snapshot.val()); }); }

Finally we need to create the HTML to render each post. We'll make a createPost function in case we want to use it in other places later. This is based on the structure of a post mocked up in class.

This example also uses the createDiv function to make each div so we don't have to repeat writing document.createElement('div') for each element.

function createDiv(_class, text) { const div = document.createElement('div'); div.classList.add(_class); div.textContent = text; return div; } function createPost(data) { const post = createDiv('post'); const text = createDiv('text', data.text); const info = createDiv('info'); const author = createDiv('author', "by " + users[data.uid]); const d = new Date(data.date); const date = createDiv('date', "on " + (d.getMonth() + 1) + '.' + d.getDate() + '.' + d.getFullYear()); post.appendChild(text); post.appendChild(info); info.appendChild(author); info.appendChild(date); /* reverse chronological order */ posts.insertBefore(post, posts.firstElementChild); }

The result will create some HTML like this:

<div class="post"> <div class="text">Post text.</div> <div class="info"> <div class="author">by Author Name</div> <div class="date"> on Post Date</div> </div> </div>