Twitter LogoFacebook Logo
Angular Project 1: Building a Social Media Site Part 9: Displaying Posts
In this video, we will retrieve the posts data and display it.
By: King

Hello, welcome to another tutorial of The Complete Angular Course. In the last tutorial, we added some code to the create post component so we can upload the post data to the Firestore database.


In this video, we will retrieve the posts data and display it. If you have not already, subscribe to the channel and follow along for this project.

Creating the Post Component

To begin, open the project from where we left off in the last session. 

In the terminal, create a component call Post and place it in the tools directory. 

ng generate component tools/Post

1) Go to the Post Component HTML page and add a mat-card element


2) Each post will have a header so use the mat-card-header element to add the header. 

3) Then add the mat-card-title element for the name of the creator, and the mat-card-subtitle element for the creator’s description.

4) After that, each post may have an image so add an image element and apply the mat-card-image directive to it so it will use the styles from Angular Material. 

For the source of the image, use the home background image that we added earlier in the project as a placeholder. 

5) Underneath the image element, add the mat-card-content element to display the message of the post.

6) Lastly, add the mat-card-actions element for our action items and then add 3 material icon elements to represent our actions.

<mat-card>
    <mat-card-header>
        <mat-card-title>Name</mat-card-title>
        <mat-card-subtitle>Description</mat-card-subtitle>
    </mat-card-header>

    <img mat-card-image src="assets/home_background.png">

    <mat-card-content>
        Like, Share, and Subscribe
    </mat-card-content>

    <mat-card-actions>
        <mat-icon></mat-icon>
        <mat-icon></mat-icon>
        <mat-icon></mat-icon>
    </mat-card-actions>

</mat-card>

For the first icon, use chat_bubble_outline to get the chat bubble image.

For the second, use favorite_border to get the heart image, 

For the last, use save, to get the floppy disk image.

<mat-icon>chat_bubble_outline</mat-icon>
<mat-icon>favorite_border</mat-icon>
<mat-icon>save</mat-icon>

Now that we have our icons, set the color of each icon to warn and then apply the action-item class for each as well.

<mat-icon class="action-item" color="warn">chat_bubble_outline</mat-icon>
<mat-icon class="action-item" color="warn">favorite_border</mat-icon>
<mat-icon class="action-item" color="warn">save</mat-icon>

Go to the Post Component CSS file and create the action-item class. 

For each item, set 

1) the left margin to .5em so the icons will be separated and 
2) the cursor to pointer. 

.action-item {
    margin-left: .5em;
    cursor: pointer;
}

Go to the Post component TypeScript file and get the value of the selector. Then add it to the Post Feed component HTML page.

@Component({
  selector: 'app-post',
  templateUrl: './post.component.html',
  styleUrls: ['./post.component.css']
})
export class PostComponent implements OnInit {

}

PostFeed Component HTML

<app-post></app-post>

<button 
   (click)="onCreatePostClick()"
   mat-fab 
   color="warn" 
   id="post-button">
   <mat-icon>add</mat-icon>
</button>

If we save the project and go to the browser, we should see the template that we made for the Posts.

Image from Codeible.com

Retrieving the Posts

Now let’s see how we can get the posts data from Firestore and display the posts. 

1) Go to the Post Feed Component TypeScript file.

2) Import the FirebaseTSFirestore class and create a Firestore object.

3) Define a function call getPosts(). 

import { FirebaseTSFirestore } from 'firebasets/firebasetsFirestore/firebaseTSFirestore';

firestore = new FirebaseTSFirestore();

getPosts(){

}

If we look at our database, the documents with the posts data are in a collection call Posts.

Image from Codeible.com

To get the documents from the collection, grab the Firestore object and call the getCollection() method. 

The method takes in an object with up to 4 properties. 

1) The first property is path. It is an array that indicates the location of the collection.

Since we want to access the Posts collection, we would put Posts for the first element in the array.

2) The second property is Where. 

It is an array to apply filters to our query. If no filters are added, it will get all the documents in the collection.

The types of filters we can use is Where , OrderBy, and Limit.

3) The third property is onComplete. It is a callback function that gets called when we received the documents from Firestore. We can use the result object to get all the documents.

4) The last property is onFail which is also a callback function, but it gets call when something went wrong during the retrieval process.

getPosts(){
    this.firestore.getCollection(
      {
        path: ["Posts"],
        where: [
          new OrderBy("timestamp", "desc"),
          new Limit(10)
        ],
        onComplete: (result) => {

        },
        onFail: err => {

        }
      }
    );
}

Now that we have a function to get our posts, we need to create an interface for the data that we’re retrieving.

After the end the class definition, define an interface call PostData. We know that each post has a comment, and the creator’s id. 

It can also have an imageUrl to represent the image of the post. Since it is an optional field, we need to put a question mark symbol before the colon. 

Make sure that each field in the interface matches the field names in Firestore.

@Component({
  selector: 'app-post-feed',
  templateUrl: './post-feed.component.html',
  styleUrls: ['./post-feed.component.css']
})
export class PostFeedComponent implements OnInit {
  ...
}

export interface PostData {
  comment: string;
  creatorId: string;
  imageUrl?: string;
}

1) Go back into the class and create an array call posts for the Post Data.

2) In the onComplete callback function of the getCollection method, grab the result object. 

It contains a property call docs which represents an array of documents that were retrieved in the collection. We can then call the forEach function to loop through all the documents.

3) Inside the loop, grab the document object and call the data() method. 

This will return all the data for the post. We can assign it to a variable to store the value.

4) Cast the data to PostData and then add each post to the posts array.

5) Lastly, go to the ngOnInit() method and call the getPosts() method. 

@Component({
  selector: 'app-post-feed',
  templateUrl: './post-feed.component.html',
  styleUrls: ['./post-feed.component.css']
})
export class PostFeedComponent implements OnInit {
  ...
  posts: PostData [] = [];

  ngOnInit(): void {

  }

  getPosts(){
   ...
  }

}

onComplete: (result) => {
     result.docs.forEach(
            doc => {
              let post = <PostData>doc.data();
              this.posts.push(post);
            }
    );
}

Modifying the Post Component

The next step is to go to the Post component TypeScript file and create an input to accept a Post document.

@Input() postData: PostData;

Then go to the Post Component HTML page and use interpolation to replace the static value from the post image with the imageUrl from the post document. 


For the comment, we’ll use the value from the post as well.

<mat-card>
    <mat-card-header>
        <mat-card-title>Name</mat-card-title>
        <mat-card-subtitle>Description</mat-card-subtitle>
    </mat-card-header>

    <img mat-card-image src="{{postData?.imageUrl}}">

    <mat-card-content>
       {{postData?.comment}}
    </mat-card-content>

    <mat-card-actions>
        <mat-icon ...></mat-icon>
        <mat-icon ...></mat-icon>
        <mat-icon ...></mat-icon>
    </mat-card-actions>

</mat-card>

Looping through all the Posts

Go to the PostFeed Component HTML page. 


Inside the post component element, use the *ngFor directive and loop through all our post. Then set the post input in the Post component with the post object that we get from the loop.

<app-post *ngFor="let post of posts" [postData]="post"></app-post>

If we save the project and go to the browser, we should see some of our posts.

Image from Codeible.com

If you notice, each post is taking up the whole width of the window which causes the images to be large.


1) Go back to the Post Feed Component HTML page. 
2) Wrap the Post component with a div element and give it a name call post-feed.

<div id="post-feed">
    <app-post *ngFor="let post of posts" [postData]="post"></app-post>
</div>

3) Go to the post-feed component CSS file and create the selector for it. 


4) Set max-width to 500px and margin-top to 5em. Lastly, center the posts by setting the left and right margins to auto. 

#post-feed {
    max-width: 500px;
    margin-top: 5em;
    margin-left: auto;
    margin-right: auto;
}

If we save the project and go to the browser, our post will look smaller.

That’s all for this tutorial. If you find this helpful, please like, share, and subscribe to support the channel.

In the next tutorial we’ll get the creator’s information and display it in the Post header. We’ll also create the reply component so users can leave comments for the post. 


Sign In