Sort data without articles using RxJS and Angular
Tags: webdev, angular, rxjs, tutorial
Published: 2022-12-03 02:55:57

## Introduction

This is day 17 of Wes Bos’s JavaScript 30 challenge and I am going to sort data without articles RxJS and Angular.

In this blog post, I describe how to use RxJS operators to covert array to Observable, use function to remove articles temporarily, compare texts to determine sort order and finally map the results to Observable variable.

### Create a new Angular project in workspace
```bash
ng generate application day17-sorted-without-articles
```

### Create Sorted List feature module
First, we create a List feature module and import it into AppModule. The feature module is consisted of SortedListComponent that encapsulates pattern matching and the comparison logic.

Then, Import ListModule in AppModule

```typescript
// list.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { SortedListComponent } from './sorted-list/sorted-list.component';

@NgModule({
  declarations: [
    SortedListComponent
  ],
  imports: [
    CommonModule
  ],
  exports: [
    SortedListComponent
  ]
})
export class ListModule { }

// app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';
import { ListModule } from './list';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    ListModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }
```

### Declare component in feature module

In List module, I declare SortedListComponent that displays the sorted data in a list.

The component will apply built-in RxJS operators and then use ngFor directive to render the sorted data in &lt;li&gt; elements.

```
src/app
├── app.component.spec.ts
├── app.component.ts
├── app.module.ts
└── list
    ├── index.ts
    ├── list.module.ts
    └── sorted-list
        ├── sorted-list.component.spec.ts
        └── sorted-list.component.ts
```

I define component selector, inline template and inline CSS styles in the file. RxJS codes will be implemented in the later sections of the blog post. For your information, <app-sorted-list> is the tag of SortListComponent.

```typescript
@Component({
  selector: 'app-sorted-list',
  template: `
    <div>
      <h1>Sort bands without articles</h1>
      <ul id="bands">
        <ng-container *ngIf="sortedBands$ | async as sortedBands">
          <li *ngFor="let band of sortedBands">{{ band }}</li>
        </ng-container>
      </ul>
    </div>
  `,
  styles:[`
    :host {
      display: block;
    }

    div {
      display: flex;
      flex-wrap: wrap;
      justify-content: center;
    }

    h1 {
      text-align: center;
      margin-bottom: 2rem;
      flex-basis: 100%;
    }

    #bands {
      list-style: inside square;
      font-size: 20px;
      background: white;
      width: 500px;
      padding: 0;
      box-shadow: 0 0 0 20px rgba(0, 0, 0, 0.05);
    }
    
    #bands li {
      border-bottom: 1px solid #efefef;
      padding: 20px;
    }
    
    #bands li:last-child {
      border-bottom: 0;
    }

    a {
      color: #ffc600;
      text-decoration: none;
    }
  `],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class SortedListComponent {

  sortedBands$ = of(['']);

  private strip(bandName: string) {
    return bandName.replace(/^(a |the |an )/i, '').trim();
  }
}
```

sortedBands$ is an Observable<string[]> and it is resolved in inline template by async pipe to render the array elements. Sorting without articles occurs when I use strip to remove articles temporarily and then compare two texts to determine their sort order.

I use `of` operator instead of `from` operator because of streams the entire array to the next operator whereas from streams one item at a time and is not applicable to sorting purpose.

Next, I delete boilerplate codes in AppComponent and render SortedListComponent in inline template.

```typescript
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { Title } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: '<app-sorted-list></app-sorted-list>',
  styles: [`
    :host {
      display: block;
    }
  `]
})
export class AppComponent {
  title = 'Day17 Sorted Without Articles';

  constructor(titleService: Title) {
    titleService.setTitle(this.title);
  }
}
```

### Write RxJS code to return sorted data
In this section, I will incrementally modify showBands$ to sort data without articles.

```typescript
// sorted-list.component.ts

import { map, of } from 'rxjs';

sortedBands$ = of(['The Plot in You', 'The Devil Wears Prada', 
    'Pierce the Veil', 
    'Norma Jean', 'The Bled', 
    'Say Anything', 
    'The Midway State', 
    'We Came as Romans', 
    'Counterparts', 
    'Oh, Sleeper', 
    'A Skylit Drive', 
    'Anywhere But Here', 
    'An Old Dog'
])
  .pipe(map(bands => ([...bands].sort((a, b) => this.strip(a) > this.strip(b) ? 1 : -1))));
```

Let’s explain each line of RxJS code

- of([….]) converts the string array into Observable
- map(bands => ([…bands].sort((a, b) => this.strip(a) > this.strip(b) ? 1 : -1))) strips articles, sorts the strings and maps the results

Finally, I have a simple page that can sort data without articles and render the sorted list subsequently.

## Final Thoughts

In this post, I show how to use RxJS and Angular to sort data without articles. the takeaway is to use RxJS of operator to convert array to Observable. Then, the array is able to stream to the next operator for further data transformation.

This is the end of the blog post and I hope you like the content and continue to follow my learning experience in Angular and other technologies.


## Resources:

1. Repo: https://github.com/railsstudent/ng-rxjs-30/tree/main/projects/day17-sorted-without-articles
2. Live demo: https://railsstudent.github.io/ng-rxjs-30/day17-sorted-without-articles/
3. Wes Bos’s JavaScript 30 Challenge: https://github.com/wesbos/JavaScript30