Creating a Dumb Component to Display GIFs
As usual, we are going to try and start by implementing a feature that moves us toward the main goal of the application as quick as possible. This is an application that displays GIFs, so we are going to start by creating our dumb/presentational component that handles displaying the GIFs.
Remember, in this application build I am going to go very light on the instructions and explanations. In some places I will be intentionally vague and leave steps out (e.g. like not reminding you to import the module for a particular component we built). If you forget to do this you should run into errors, and this will be good practice in reading and trying to decipher the errors. Again, I want to reiterate that this is not because I expect this to be easy for you now. I expect that this will likely cause most people to get stuck on things, and that is the point.
Whenever we are implementing something we haven’t seen before, I will still explain it thoroughly.
Create an interface for GIFs
Create the following interface at
src/app/shared/interfaces/gif.ts
:
export interface Gif {
src: string | null;
author: string;
name: string;
permalink: string;
title: string;
thumbnail: string;
comments: number;
loading?: boolean;
dataLoaded?: boolean;
}
This might seem like a little bit more than we usually do. We will not be making use of all of these fields immediately, but eventually this is all of the data that we are going to want to retrieve for a GIF from Reddit.
We are also going to be creating a lot of different interfaces for this application, so for convenience sake, we are going to create a single index.ts
file that we can use to import any of our interfaces by exporting them all from that file.
Create a file at
src/app/shared/interfaces/index.ts
and add the following:
export * from './gif';
Any time we add a new interface, we will export it from this file.
Create the Component
Create a file at
src/app/home/ui/gif-list.component.ts
and add the following:
import {
ChangeDetectionStrategy,
Component,
Input,
NgModule,
} from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { Gif } from '../../shared/interfaces';
@Component({
selector: 'app-gif-list',
template: `
<ion-list lines="none">
<div class="gif" *ngFor="let gif of gifs; trackBy: trackByFn">
<ion-item button detail="false">
<video
playsinline
poster="none"
preload="none"
[loop]="true"
[muted]="true"
[src]="gif.src"
></video>
<ion-label>{{ gif.title }}</ion-label>
</ion-item>
</div>
</ion-list>
`,
styles: [
`
ion-list {
padding: 0;
}
ion-label {
margin: 0;
padding: 10px 0;
overflow: auto;
}
.gif ion-item {
--inner-padding-end: 0;
--padding-start: 0;
position: relative;
}
.gif ion-spinner {
margin: auto;
position: absolute;
left: 0px;
right: 0px;
z-index: 1;
background-color: var(--ion-color-dark);
border: 10px solid var(--ion-color-dark);
border-radius: 5px;
padding: 20px;
}
.comments {
display: block;
width: 100%;
margin-top: 5px;
text-align: right;
color: var(--ion-color-medium);
}
ion-list-header {
align-items: center;
background-color: var(--ion-color-light);
border-bottom: 10px solid var(--ion-color-medium);
}
ion-list-header ion-button {
margin: 0;
}
.preload-background {
width: 100%;
height: auto;
}
video {
width: 100%;
height: auto;
margin: auto;
background: transparent;
}
`,
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class GifListComponent {
@Input() gifs!: Gif[];
trackByFn(index: number, gif: Gif) {
return gif.permalink;
}
}
@NgModule({
imports: [CommonModule, FormsModule, IonicModule],
declarations: [GifListComponent],
exports: [GifListComponent],
})
export class GifListComponentModule {}