Wanna see something cool? Check out Angular Spotify 🎧

Angular Jira Clone Part 08 - Create placeholder loading (like Facebook's cards loading)

It is common to display a loading spinner to keep visitors entertained while the page is still loading. And there are two modes of a loading spinner:

Mode Description
determinate Standard progress indicator fills from 0% to 100%
indeterminate Indicates that something is happening without conveying discrete progress

Spinners and progress bars are explicit loading paradigms. They focus the user on communicating a loading period and, more often than not, are blocking user interaction until a layout has loaded enough to be useful.

No one wants to wait 🤣

Introducing placeholder loading, it is usually grey or neutral-toned filled shapes, meet the user instantly upon user interaction with calls to action or links. The placeholders (the so-called “bones” of the skeleton) are then replaced with the actual site content, and the illusion is complete. That’s what skeleton screens do: create the illusion of an instant transition.

A famous example is Facebook’ newsfeed.

Angular Jira Clone Part 08 - Create placeholder loading (like Facebook's cards loading) in Angular

Based on a research, displaying a skeleton screen will cause humans to perceive a loading period as being shorter in duration

Jira clone placeholder loading

On jira.trungk18.com, I also need a placeholder loading for an issue detail. I could display a spinner, but too much spinner doesn’t seem like an excellent way to interact with your user. 😂

The standard-issue detail will have two columns layout.

Angular Jira Clone Part 08 - Create placeholder loading (like Facebook's cards loading) in Angular

I translated the above detail layout to gray rect and circle SVG at the end.

Angular Jira Clone Part 08 - Create placeholder loading (like Facebook's cards loading) in Angular

How to create a placeholder loading

I used ngneat/content-loader for this purpose. You need to prepare an SVG structure, and content-loader will do the rest of the work for you, including the animation.

Install

yarn add @ngneat/content-loader

Usage

import { ContentLoaderModule } from '@ngneat/content-loader'

@NgModule({
  imports: [ContentLoaderModule],
})
export class AppModule {}

And specify your placeholder template:

<content-loader>
  <svg:rect x="0" y="0" rx="3" ry="3" width="250" height="10" />
  <svg:rect x="20" y="20" rx="3" ry="3" width="220" height="10" />
  <svg:rect x="20" y="40" rx="3" ry="3" width="170" height="10" />
  <svg:rect x="0" y="60" rx="3" ry="3" width="250" height="10" />
  <svg:rect x="20" y="80" rx="3" ry="3" width="200" height="10" />
  <svg:rect x="20" y="100" rx="3" ry="3" width="80" height="10" />
</content-loader>

Warning: Safari renders the SVG in black in case your Angular application uses the <base href="/"/> tag in the <head/> of your index.html. Refer to the input property baseUrl on the library documentation to fix this issue.

What is svg:rect

There are several basic shapes used for most SVG drawing. SVG has some predefined shape elements that can be used by developers:

  • Rectangle <rect>
  • Circle <circle>
  • Ellipse <ellipse>
  • Line <line>
  • Polyline <polyline>
  • Polygon <polygon>
  • Path <path>

For placeholder loading, the most used two are rect and circle.

For Angular to work, you need to specify svg:rect instead of purely rect. If you use rect only, it will give you an error

Explanation

In detail for rect, it is a basic SVG shape that draws rectangles, defined by their position, width, and height. The rectangles may have their corners rounded.

<svg:rect x="20" y="100" rx="3" ry="3" width="80" height="10" />
Attribute Description Explain
x left position of the rectangle x="20" places the rectangle 20px from the left margin
y top position of the rectangle y="100" places the rectangle 100px from the top margin
width & height height and the width of the rectangle width="80" mean 80px wide and height="10" mean 10px tall
rx radius on the x-axis (horizontal corner) rx="3" mean 3px radius on the x-axis
ry radius on the y-axis (vertical corner) ry="3" mean 3px radius on the y-axis

How to create Jira clone placeholder loading

Pretty straight forward, based on the issue detail layout with two columns. I went ahead and wrote the following code. You’re all set!

<content-loader
  [viewBox]="'0 0 940 260'"
  [backgroundColor]="'#f3f3f3'"
  [foregroundColor]="'#ecebeb'"
>
  <svg:rect x="0" y="0" rx="3" ry="3" width="627" height="24" />
  <svg:rect x="0" y="29" rx="3" ry="3" width="506" height="24" />
  <svg:rect x="0" y="77" rx="3" ry="3" width="590" height="16" />
  <svg:rect x="0" y="100" rx="3" ry="3" width="627" height="16" />
  <svg:rect x="0" y="123" rx="3" ry="3" width="480" height="16" />
  <svg:rect x="0" y="187" rx="3" ry="3" width="370" height="16" />
  <svg:circle cx="18" cy="239" r="18" />
  <svg:rect x="46" y="217" rx="3" ry="3" width="548" height="42" />
  <svg:rect x="683" y="3" rx="3" ry="3" width="135" height="14" />
  <svg:rect x="683" y="33" rx="3" ry="3" width="251" height="24" />
  <svg:rect x="683" y="90" rx="3" ry="3" width="135" height="14" />
  <svg:rect x="683" y="120" rx="3" ry="3" width="251" height="24" />
  <svg:rect x="683" y="177" rx="3" ry="3" width="135" height="14" />
  <svg:rect x="683" y="207" rx="3" ry="3" width="251" height="24" />
</content-loader>

Source code and demo

  1. https://stackblitz.com/edit/angular-placeholder-loader-like-facebook
  2. issue-loader.component.html

See all tutorials for Jira clone

References

Published 7 Nov 2020

Read more

Get the last items of an array using array.slice()
Angular Jira Clone Part 07 - Build a rich text editor
How to iterate over objects in TypeScript
How to copy an object from the Chrome inspector console as code
Use async functions instead of callbacks for asynchronous code

Follow @tuantrungvo on Twitter for more!