Deployment and Developer a PWA Splash Screen with Angular 8

Deployment and Developer a PWA Splash Screen with Angular 8

It's very easy to convert a normal Angular App to a PWA. You just run a few CLI commands, create an icon and configure theme colors. But there is no such thing as a splash screen out of the box. Our goal is to show a splash screen to the user whenever he opens the app.

When you’ve already created an (Angular) PWA, you probably have noticed, that the service worker will perform a self-update, but in the background. That means when you deploy a new version of your app on your server, the next time the user opens the app it will update itself automatically in the background. But in the current session, the user sees the old version of the app.

This happens because the new service worker is indeed downloaded, but not activated yet. It will activate only on the next visit. But this can be tricky because oftentimes you not only have a front-end app but also a back-end server and maybe you have major breaks in your API. So the old version of the front-end is not compatible with the new API. If this is the case, your users must be always using the newest version of the app.

And I will show you, how to do that.

What is our goal?

It’s very easy to convert a normal Angular App to a PWA. You just run a few CLI commands, create an icon and configure theme colors. But there is no such thing as a splash screen out of the box.

Our goal is to show a splash screen to the user whenever he opens the app. While the splash screen is open, we want to check for updates and if an update is found we reload the app. If no update is found we remove the splash screen.

This is one cool example of a splash screen on dribbble.com we could realize with the following tutorial:

How to check for updates

Angular provides a service called SWUpdate which holds all the information around your app and possible updates.

class SwUpdate {
   available: Observable<UpdateAvailableEvent>
   activated: Observable<UpdateActivatedEvent>
   isEnabled: boolean
   checkForUpdate(): Promise<void>
   activateUpdate(): Promise<void>
 }

source: https://angular.io/api/service-worker/SwUpdate

What are these properties and methods are for?

available This observable emits whenever a new version is found. It searches for new version on startup or whenever you use checkForUpdate() .

activated This observable emits whenever a new version has been activated. This is normally the case when a new version is available and the user reloads the application. You could use that for showing a tutorial of the new version whenever a user sees it for the first time.

isEnabled This function is needed to be sure that the current browser supports service workers and the service worker is enabled.

checkForUpdate() This method triggers an update check. Unfortunately, it doesn’t return a value. So you have to use it in combination with SwUpdate.available .

activateUpdate() This method forces the service worker to activate a new version, but it’s still only used on the next loading.

So, how can we use this in combination with a splash screen?

First of all, we need a splash screen, which is visible by default.

@Injectable({
    providedIn: 'root'
})
export class PwaService {

    constructor(
        private appRef: ApplicationRef,
        private swUpdate: SwUpdate,
    ) {
        if (this.swUpdate.isEnabled) {
            this.appRef.isStable.pipe(
                first(isStable => isStable === true),
                switchMap(() => this.swUpdate.available),
            ).subscribe(() => {
                this.swUpdate.activateUpdate().then(() => document.location.reload());
            });
        }
    }

    checkForUpdate(): Observable<boolean> {
        const waitFor = 1000;

        if (this.swUpdate.isEnabled) {
            const available$ = this.swUpdate.available.pipe(
                mapTo(true),
                timeout(waitFor),
                catchError(() => of(false)),
            );

            return fromPromise(this.swUpdate.checkForUpdate()).pipe(
                switchMap(() => available$),
            );
        }

        return timer(waitFor).pipe(mapTo(false));
    }
}
@Component({
    selector: 'app-splash-screen',
    template: `
        <div class="splash-screen" *ngIf="show" @fadeOut>
             // Your custom splash screen design
        </div>
    `,
    animations: [
        // the fade-in/fade-out animation.
        trigger('fadeOut', [
            transition(':leave', [
                query(':leave', animateChild(), {optional: true}),
                animate(300, style({opacity: 0}))
            ]),
        ]),
    ],
    styles: [`
        .splash-screen {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            z-index: 9999;
        }
    `],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplashScreenComponent implements OnInit {
    show = true;

    constructor(
        private pwaService: PwaService,
        private cdr: ChangeDetectorRef,
        private appRef: ApplicationRef,
    ) {
    }

    ngOnInit() {
        this.pwaService.checkForUpdate()
            .subscribe(result => {
                this.show = result;
                this.cdr.detectChanges();
            });
    }
}

Github

This splash screen is a simple Angular component that has position: absolute and lays above everything else. When we are sure that there is no update available, we fade the splash screen out. This component should be added to your root AppComponent .

Now we need the PwaService :

@Injectable({
    providedIn: 'root'
})
export class PwaService {

    constructor(
        private appRef: ApplicationRef,
        private swUpdate: SwUpdate,
    ) {
        if (this.swUpdate.isEnabled) {
            this.appRef.isStable.pipe(
                first(isStable => isStable === true),
                switchMap(() => this.swUpdate.available),
            ).subscribe(() => {
                this.swUpdate.activateUpdate().then(() => document.location.reload());
            });
        }
    }

    checkForUpdate(): Observable<boolean> {
        const waitFor = 1000;

        if (this.swUpdate.isEnabled) {
            const available$ = this.swUpdate.available.pipe(
                mapTo(true),
                timeout(waitFor),
                catchError(() => of(false)),
            );

            return fromPromise(this.swUpdate.checkForUpdate()).pipe(
                switchMap(() => available$),
            );
        }

        return timer(waitFor).pipe(mapTo(false));
    }
}
@Component({
    selector: 'app-splash-screen',
    template: `
        <div class="splash-screen" *ngIf="show" @fadeOut>
             // Your custom splash screen design
        </div>
    `,
    animations: [
        // the fade-in/fade-out animation.
        trigger('fadeOut', [
            transition(':leave', [
                query(':leave', animateChild(), {optional: true}),
                animate(300, style({opacity: 0}))
            ]),
        ]),
    ],
    styles: [`
        .splash-screen {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
            z-index: 9999;
        }
    `],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class SplashScreenComponent implements OnInit {
    show = true;

    constructor(
        private pwaService: PwaService,
        private cdr: ChangeDetectorRef,
        private appRef: ApplicationRef,
    ) {
    }

    ngOnInit() {
        this.pwaService.checkForUpdate()
            .subscribe(result => {
                this.show = result;
                this.cdr.detectChanges();
            });
    }
}

Github

Important notice: The _ServiceWorkerModule_ waits for the application to stabilize before registering any service worker. Every use of observables prevents the application from becoming stable, therefore we need to use _ApplicationRef.isStable_ and wait with every update check we want to do.

In the PwaService constructor we subscribe to the available stream and every time we find a new version, we activate it and perform a document.location.reload() after activation.

Then we implement a method checkForUpdate() which does multiple things:

  1. It checks if service workers are enabled. If not, it returns an observable that directly maps to false (I just implemented a short waiting time, because a splash screen which hides immediately could cause a flickering effect).
  2. When service workers are enabled it performs the SwUpdate.checkForUpdate() method and maps to the available stream, which should emit immediately after the SwUpdate.checkForUpdate() promise resolves when an update is found. Because we don’t get any information when no update is found, the available stream gets a timeout, which maps to false when no update is found.

After that, we just need to set show to the result of the checkForUpdate() method, which is either true or false . This lasts 1 second in minimum so the splash screen doesn’t flicker.

Conclusion

With just a few tricks it’s easy to implement a “splash screen like” feature into your Angular app.

Happy Coding! Thank you for reading !

Angular Angular8 JavaScript Typescript Web Design

Bootstrap 5 Complete Course with Examples

Bootstrap 5 Tutorial - Bootstrap 5 Crash Course for Beginners

Nest.JS Tutorial for Beginners

Hello Vue 3: A First Look at Vue 3 and the Composition API

Building a simple Applications with Vue 3

Deno Crash Course: Explore Deno and Create a full REST API with Deno

How to Build a Real-time Chat App with Deno and WebSockets

Convert HTML to Markdown Online

HTML entity encoder decoder Online

Mobile Responsive Web Design

Skenix Infotech is a top-rated responsive website design company that provides creative responsive web design services at reasonable prices. Get in touch today!

Web Design Service in USA

Looking for designers for your business website design? We at Data EximIT offer our best **[web designing services in the USA](https://www.dataeximit.com/services/ "web designing services in the USA")** with the aim of craft your website more...

Angular + Typescript = Powerful Web Apps

This presentation will cover the basics of Angular and the advantages of TypeScript – a language that adds features to JavaScript, including strong typing. You will learn about data binding, event binding, routing, and observables.

Latest Web Design and Development Trends To Follow In 2020

Web development is a dynamic field. With the emergence of new technologies each year, we can observe web development trends changing to a greater or lesser extent. In 2020 too, new technologies have emerged and

Industry-Standard Web Development Techniques for Angular

This post discusses some of the best approaches used for building responsive and interactive web apps in Angular.