v19 launch sale ends in ... Get 25% off BUY NOW
3d cartoon hands holding a phone

Unlock full course by purchasing a membership

Lesson 9

Styling and Refinements

STANDARD

Styling and Refinements

Now we just have a few remaining loose ends to finish up — there are a few minor changes we are going to make just to provide a better experience in the application, and to make it look a little nicer.

Adding Titles and Comments

At the moment, we are only displaying the actual gif, but it would be nice to see the title as well. We will update our GifListComponent to include this, as well as linking to the comment thread on Reddit for the gif.

Before we do that, we are going to create a little utility.

Create a file at src/app/shared/utils/injection-tokens.ts and add the following:

import { InjectionToken } from '@angular/core';

export const WINDOW = new InjectionToken<Window>('The window object', {
  factory: () => window,
});

We have seen something like this before — we did a similar thing when accessing the localStorage API. The reasoning is the same again here — the window object is a browser API and an Angular application does not necessarily always run in the context of a browser. An injection token is a safer design because we can provide alternate implementations based on the environment the application is running in. We are not doing that here, and technically it isn’t necessary if we know our application is only ever going to run in the browser context, but it is a good principle to keep in mind.

I will leave you a bit of an assignment before we continue. We are going to implement a few features all at once for our GifListComponent. Take your best shot at implementing the following and then I will post my solution — you will likely need to look up the Angular Material documentation.

  • Use an Angular Material toolbar to display the title of each gif
  • Inject our WINDOW token and use it to launch the link for the particular gif in the browser when the user clicks somewhere in the toolbar. My solution uses an Angular Material icon as the link to click
  • Add a message that displays if there are no gifs

Update the GifListComponent to reflect the following:

import { Component, input, inject } from '@angular/core';
import { WINDOW } from '../../shared/utils/injection-tokens';
import { Gif } from '../../shared/interfaces';
import { MatToolbarModule } from '@angular/material/toolbar';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { GifPlayerComponent } from './gif-player.component';

@Component({
  selector: 'app-gif-list',
  template: `
    @for (gif of gifs(); track gif.permalink){
      <div>
        <app-gif-player
          [src]="gif.src"
          [thumbnail]="gif.thumbnail"
          data-testid="gif-list-item"
        ></app-gif-player>
        <mat-toolbar color="primary">
          <span>{{ gif.title }}</span>
          <span class="toolbar-spacer"></span>
          <button
            mat-icon-button
            (click)="window.open('https://reddit.com/' + gif.permalink)"
          >
            <mat-icon>comment</mat-icon>
          </button>
        </mat-toolbar>
      </div>
    } @empty {
      <p>Can't find any gifs 🤷</p>
    }
  `,
  imports: [
    GifPlayerComponent,
    MatToolbarModule,
    MatIconModule,
    MatButtonModule,
  ],
  styles: [
    `
      div {
        margin: 1rem;
        filter: drop-shadow(0px 0px 6px #0e0c1ba8);
      }

      mat-toolbar {
        white-space: break-spaces;
      }

      p {
        font-size: 2em;
        width: 100%;
        text-align: center;
        margin-top: 4rem;
      }
    `,
  ],
})
export class GifListComponent {
  gifs = input.required<Gif[]>();
  window = inject(WINDOW);
}
STANDARD
Key

Thanks for checking out the preview of this lesson!

You do not have the appropriate membership to view the full lesson. If you would like full access to this module you can view membership options (or log in if you are already have an appropriate membership).