NativeScript ListView Skeleton Screens with Angular & RxJS ☠️
Tags: nativescript, angular, rxjs, ux
Published: 2018-10-21 18:11:38

---
title: NativeScript ListView Skeleton Screens with Angular & RxJS ☠️
published: true
description: Data connections still vary in speed out there. Give your users a preview of what your UI looks like to help ease the pain of waiting in your NativeScript apps with a skeleton screen using Angular and RxJS.
tags: NativeScript, Angular, RxJS, UX 
---

It's just about Halloween so now seems to be the perfect time to discuss a technique I've started using more lately: skeleton screens.


### Skeleton Screens

If you've used just about any major website in the last couple of years you've probably seen skeleton screen. I particularly like them because they give you an idea of what to expect before the data loads. With a mobile device, they make extra sense to me since at times the user's data connection could be particularly slow. 

<figure>
  <img src="https://thepracticaldev.s3.amazonaws.com/i/t82y10c5vl7w5l2vk16j.jpg" alt="Skeletons being used on Slack" id="fig_id"><figcaption>Skeletons being used on Slack.</figcaption>
</figure>

### NativeScript
If you aren't familiar with NativeScript, you should really check it out. NativeScript is my favorite mobile development framework, between having 100% access to Native API's, Angular support, and their online playground where you can write code in your browser and test it on your phone. These features and more make it's the hands down the best way to develop multi-platform apps. 

### ListView Skeletons in NativeScript
Normally we could approach this with a `ngIf` and a `else`, something like:

```html
<StackLayout *ngIf="data$ | async; else skeletons">
  <!---View of data after Loaded -->
</StackLayout>

<ng-template #skeletons>
  <!--- Skeletons Here -->
</ng-template>
```


This way before our observable with my response object emits a value it will display a different template. This pattern works pretty well for both NativeScript and the Web (replace `StackLayout` with `div`). 

However, for this use case, we have a long list of items that we are displaying so it is best to use a ListView for performance reasons. Because we want our skeletons to mimic the UI as much as possible we will want them in a ListView as well. 

<figure>
  <img src="https://thepracticaldev.s3.amazonaws.com/i/hr8882a826pfgu3zbtvo.png" alt="Screenshot of my ListView" id="fig_id">
<figcaption>Screenshot of my ListView </figcaption>
</figure>

If we wanted we could use the same pattern as above and have two separate ListViews on my page. One for the content, one for my skeletons. This is not a very efficient use of our layout and will make it harder to make changes to the UI since it will be decoupling the skeletons from the end result.

### ListView Template Selectors 

NativeScript's ListView has an easy way to alternate between templates. By defining a `itemTemplateSelector` callback function and giving each template a key with the `nsTemplateKey` attribute, we are able to swap layouts. Every time a ListView loads an item to display to the user, the template selector function fires and determines which template to use for that item. The last thing we need to do is then pass our template selector callback to our ListView via the input.
 
```html
<ListView [items]="genres$ | async" [itemTemplateSelector]="templateSelector">
    <ng-template nsTemplateKey="template" let-item="item" let-index="index">
        <GridLayout class="music-genre" rows="*" columns="55,*">
        <Label row="0" col="0" [text]="index + 1" class="number"></Label>
        <Label row="0" col="1" [text]="item" class="genre"></Label>
        </GridLayout>
    </ng-template>
    <ng-template nsTemplateKey="skeleton">
        <GridLayout class="music-genre skeleton" rows="*" columns="55,*">
            <Label row="0" col="0" text=" " class="number number-skeleton"></Label>
            <Label row="0" col="1" text=" " class="genre genre-skeleton"></Label>
        </GridLayout>
    </ng-template>
</ListView>
```
_Our NativeScript Angular Template with a ListView to switch between a skeleton and normal template_

A `itemTemplateSelector` callback function has 3 parameters, the current item, that items index, and all the items currently in the list. 
 
```typescript
 templateSelector(item: any, index: number, items: any[]) {
    return 'template';
};
```
_Template selector function that always returns the type of `template`_


### RxJS startWith Operator

With the above template selector, we sill only see the genre items. We will need a way to load an array of "skeletons" first, then when we get our response back from the server replace the skeleton array with the results data array. This is where RxJS's `startWith` operator comes into play. What we need to do is pass an array of objects to the pipeable operator `startsWith`. We then "pipe" this operator when we set the `genres$` observable property in the components `ngOnInit` function. Now when we subscribe to the  `genres$` observable it will emit two values. First the array of skeletons, then the results of our HTTP request, when it completes.

What I like to do is declare a `ISkeleton` interface which is an object that has a boolean property on it called `skeleton`. Then create an array of objects each with there own `skeleton` property set to true. This is then the array that is passed to the `startsWith` operator to be emitted first by the `genres$` observable.


```typescript

interface ISkeleton{
    skeleton: boolean;
}

const SKELETONS: ISkeleton[]  = [
    { skeleton: true },
    { skeleton: true }
    ... // since this is for a listView I have quite a few of these. 
];

@Component({...})
export class HomeComponent implements OnInit {

    genres$: Observable<ISkeleton[] | string[]>;

    constructor(private genreService: GenreService) {
    }

    ngOnInit() {
        // Get a list of genre's from the genre service. but first, start by  
        // emmiting the SKELETONS array.
        this.genres$ = this.genreService.getGenres()
            .pipe(startWith(SKELETONS));
    }

```

Now everything is just about hooked up. However, if we run our app we are still not seeing our skeleton templates. The last step is to update our template selector function. All we need to do is check if the `item` object that is passed to it has a skeletons property on it. If that returns truthy, then have our template selector function return the key of 'skeleton'.

```typescript
templateSelector(item) {
    if (item.skeleton) {
        return 'skeleton';
    }
    return 'template';
};
```


### Finished Product

<figure>
  <img src="https://thepracticaldev.s3.amazonaws.com/i/79291ev5eya6zt8o8egj.gif" alt="All tied together" id="fig_id">
</figure>

As you can see in the above gif when a user first comes to this view they are greeted with a list of skeletons immediately. Then once the HTTP request completes the view switches to a list of musical genres. We have been primed so to speak for this layout with the skeletons.

Setting up our skeleton screens this way is only the beginning, there is so much more you could do with this pattern especially when it comes to animations. Because of the power of NativeScript's ListView, Angular and RxJS we have a very succinct code base to build upon.  

You can view a working sample on the [NativeScript Playground here] (https://play.nativescript.org/?template=play-ng&id=1xU1Fw&v=18). _Just a disclaimer it's currently styled to look good on iOS since I don't have an Android phone to test on currently._

Thanks for reading, I hope you enjoyed my take on this pattern. If you did, please share with your friends and co-workers. I'd really enjoy any feedback you have via the comments below. Or if you have your own take on skeleton screens in NativeScript let's see those too!