lifelong learner — urip iku urup, currently working on accenture.

chapter 8 – sort pipe ascending & descending

1
Degananda.com -

kita dapat menggunakan lebih dari satu pipe pada angular. Terlebih lagi antar pipe dapat dilakukan chaining. Sehingga , kita dapat memanipulasi data yang ada  (yang diproses pada pipe) secara bergantian untuk mencapai fungsi tertentu. Silahkan simak ulasan chapter-8 ini untuk mempelajari contoh proses pipe chaining.

Pada tutorial chapter-8 ini akan membuat sort pipe yang digabungkan dengan search pipe yang telah kita buat pada chapter 6 dan 7. Tujuannya adalah untuk mempelajari proses chaining itu sendiri. Secara garis besar, proses chain akan dimulai dari pipe yang berada disebelah kiri. Sehingga urutannya mulai dari kiri ke kanan. Jika anda memiliki data yang diproses oleh dua pipe berbeda namun berurutan maka gunakanlah aturan diatas.

Memisahkan pipe sangat lah penting karena angular tersusun dari komponen – komponen kecil yang kemudian disatukan menjadi satu untuk membentuk suatu aplikasi. Maka begitu juga dengan pipe. Setiap pipe harus memiliki satu fungsi khsus. Mengapa ? jawabannya sangat sederhana yakni untuk reuseable & tingkat maintainabilitas/pengelolaan dari source code. Setiap komponen wajib memiliki fungsi khusus sehingga sangat mudah untuk mengelolalnnya. Bayangkan jika pipe untuk search dan sort kita gabungkan menjadi satu maka ketika proses debugging akan sangat susah. Itu hanya dua fungsi pipe dijadikan satu bagaimana jika lima pipe kita jadikan satu ? tentunnya sangat menyusahkan bagi kita maupun orang lain yang bekerja dalam satu project. Oleh karena itu pipe chaining sangatlah penting.

Pre-requisiites

untuk dapat mengikuti tutorial pada chapter 8 ini anda wajib mengikuti chapter 7  dan harus mengerti mengenai beberapa hal-hal berikut dibawah ini :

  1. Membuat custom pipe
  2. Mengaplikasikan custom pipe pada directive ngFor

Jika anda belum mengerti mengenai custom pipe dan methode untuk mengaplikasikannya anda dapat mengikuti ulasan-ulasan sebelumnya mengenai custom pipe. Namun, sebenarnya hal tersebut tidak menjadi keharusan karena anda juga dapat mengikutinnya dengan membaca ulasan ini.

What we build ?

Kita akan membuat fitur sort atau mengurutkan untuk aplikasi angular note. Data yang diurutkan adalah data note yang kita buat (pada form). terdapat dua jenis sort yakni ascending dan juga descending. Ascending untuk mengurutkan data berdasarkan alfabet mulai dari A sedangkan descending untuk mengurutkan yang berkebalikan dari ascending yakni mulai dari Z.

Hal yang menariknya adalah pipe tersebut akan bekerja  (tidak bersamaan) dengan pipe search. Sehingga hasil search akan tampil juga sesuai dengan tipe sort yang dipilih (ascending atau descending). Berikut ini adalah UI / tampilan dari aplikasi pada chapter – 8 ini.

anda dapat melihat demo untuk sort pipe dan search pipe pada link dibawah ini.

http://demo.degananda.com/angular/chapter-8/

untuk memudahkan anda dalam mengikuti ulasan ini , anda juga dapat mengclone atau mengunduh source code yang digunakan pada chapter ini di :

https://github.com/degananda/angular-note/tree/8.0

lets code

Array sort

Sebelum itu kita akan membahas bagaimana melakukan sort (array) pada javascript. karena hal ini adalah core function dari sort pipe. Penulisan fungsi sort ini kami tulis menggunakan format typescript namun anda juga dapat menuliskan menggunakan javascript seperti biasannya.

Array sort memiliki format

array.sort()

di dalamnya memiliki callback function berupa nilai a dan b. Nilai a adalah nilai array pada urutan awal sedangkan nilai b adalah nilai array pada urutan a+1 atau setelah index a. Contohnya pada array [1,2,3,4,5]. Fungsi callback yang memiliki parameter a dan b akan mengecek masing-masing kombinasi berurutan pada array tersebut. 1 dan 2 , 2 dan 3 , 3 dan 4 dan seterusnya.

Callback tersebut dapat kita gunakan untuk membandingkan nilai sebelum dan setelahnya untuk melakukan sorting secara “ASCENDING” dengan cara membadingkan a dan b. Jika a > b maka akan mereturn “1” artinnya nilai tersebut memiliki index(pada alphabet) yang lebih besar, jika “-1” memiliki index yang lebih kecil sedangkan return nilai “0” maka sama.  lalu bagaimana ketika kita ingin melakukan sort decending ? javascript memiliki fungsi .reverse untuk membalikan array. Sehingga untuk melakukan descending maka

  1. sort secara ascending
  2. lakukan fungsi array.reverse

Implementasi kode javascript untuk kasus diatas adalah sebagai berikut ini.

value.sort(
      (a : any,b : any) => {
          // melakukan descending sort.
          let noteA = a.isi_note;
          let noteB = b.isi_note;
          if (noteA < noteB) {
            return -1;
          } else if (noteA > noteB) {
            return 1;
          } else {
            // note sama
            return 0;
          }
      }
    );

implemenasi pada angular (komponen & pipe)

1. Membuat custom pipe

ng g pipe pipe-sort

2. Implementasi potongan kode sort diatas pada pipe

berikut ini adalah cara melakukan sorting pada data note kita dengan menggunakan metode array sort dan array reverse (untuk descending).

import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
  name: 'pipeSort',
  pure : false
})
export class PipeSortPipe implements PipeTransform {

  transform(value: Array<string>, searchType: string): any {
    value.sort(
      (a : any,b : any) => {
          // melakukan descending sort.
          let noteA = a.isi_note;
          let noteB = b.isi_note;
          if (noteA < noteB) {
            return -1;
          } else if (noteA > noteB) {
            return 1;
          } else {
            // note sama
            return 0;
          }
      }
    );
    if(searchType.toLocaleLowerCase() == "desc"){
      value.reverse();
    }
    return value;
  }

}

3. Menambahkan beberapa elemen pada com-listnote.component.html

kita akan menambahkan beberapa hal berikut ini :

  1. “form” select untuk mendapatkan nilai dari tipe sort. asc untuk ascending dan desc untuk descending
  2. hasil dari form select tersebut akan kita tampilkan / render pada DOM.
  3. pipe sort akan menerima input dari select untuk menentukan ascending atau descending.

form select yang kami gunakan menggunakan directive *ngModel which is membutuhkan modul FormModule dari package angular/forms pastikan telah mengimport dan menaruhnya pada metadata imports di @ngModule. Berikut ini adalah apps.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

// component
import { AppComponent } from './app.component';
import { ComNoteComponent } from './com-note/com-note.component';
import { PipeSensorPipe } from './pipe-sensor.pipe';
import { FormNoteComponent } from './form-note/form-note.component';
import { ComListnoteComponent } from './com-listnote/com-listnote.component';

// material & animations
import { 
  MdButtonModule, 
  MdInputModule,
  MdListModule,
  MdToolbarModule,
  MdIconModule,
  MdSnackBarModule,
  MdTooltipModule,
  MdMenuModule,
  MdCardModule,
  MdProgressSpinnerModule,
  MdSelectModule,
  MdOptionModule
} from '@angular/material';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

// routing
import { myRouter } from './app.router';

// services
import { ServiceNoteService } from './service-note.service';
import { ComAddnoteComponent } from './com-addnote/com-addnote.component';
import { PipeSearchPipe } from './pipe-search.pipe';
import { ComSearchComponent } from './com-search/com-search.component';
import { ComLoadingComponent } from './com-loading/com-loading.component';
import { PipeSortPipe } from './pipe-sort.pipe';

// dari newbie untuk newbie
@NgModule({
  declarations: [
    AppComponent,
    ComNoteComponent,
    PipeSensorPipe,
    FormNoteComponent,
    ComListnoteComponent,
    ComAddnoteComponent,
    PipeSearchPipe,
    ComSearchComponent,
    ComLoadingComponent,
    PipeSortPipe
  ],
  imports: [
    BrowserModule,
    ReactiveFormsModule,
    FormsModule,
    HttpModule,
    myRouter,
    BrowserAnimationsModule,
    // material component
    MdButtonModule,
    MdInputModule,
    MdListModule,
    MdToolbarModule,
    MdIconModule,
    MdSnackBarModule,
    MdTooltipModule,
    MdMenuModule,
    MdCardModule,
    MdProgressSpinnerModule,
    MdSelectModule,
    MdOptionModule
    // end of material component
  ],
  providers: [
    ServiceNoteService
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

berikut ini adalah kode untuk com-listnote.component.html untuk mengakomodasi kondisi diatas

<md-toolbar color="primary">Angular Note &mdash; Chapter 8.0</md-toolbar>
<!-- search form -->
<app-com-search (searchQueryElement)="doSearch($event)" (onSearchLoading)="onLoadingChange($event)"></app-com-search>
<!-- end of search form -->

<!-- add note form -->
<app-com-addnote></app-com-addnote>
<!-- end of add note form -->



<md-list style="width: 100%;">  

    <!-- loading component -->
    <app-com-loading *ngIf="onSearchLoading"></app-com-loading>
    <!-- end of loading component -->

    <div *ngIf="!onSearchLoading">
        <div style="margin-left: 50px; margin-right: 50px;">
            <!-- sort option -->
            <div style="float: right;">
                <md-select placeholder="pilih tipe sort" [(ngModel)]="searchTypeValue">
                    <md-option *ngFor="let sortoption of sortOption" [value]="sortoption.value">
                    {{sortoption.viewValue}}
                    </md-option>
                </md-select>
            </div>
            <div style="clear:both;"></div>

            <p> Tipe sort : {{searchTypeValue}} </p>

            <div *ngFor="let note of (serviceNoteService.listNote | pipeSort:searchTypeValue | pipeSearch:searchQuery)">  
                    <app-com-note [isiNote]="note" (onDelete)="onDeleteNote($event)"></app-com-note>
            </div>
        </div>
    </div>

    <div *ngIf="listNote.length <= 0 && !onSearchLoading">
        <div style="margin-left: 50px; margin-right: 50px; color: #3d3d3d;">
            <div style="width: 100%; background: #fafafa; padding: 50px 0px 50px 0px; text-align: center;">      <md-icon style="font-size: 70px; color: #3F51B5; display: inline;">description</md-icon><br />
                <b>Belum ada data</b> pada sistem angular-note<br /> silahkan masukan note melalui form diatas.
            </div>
        </div>
    </div>

</md-list>

dapat kiat lihat bahwa pipeSort kita letakan disebelah kiri pipeSearch. Hal ini akan mengakitbatkan proses chaining. Sehingga data akan dilakukan sort terlebih dahulu baru dilakukan search. Pipe sort dan pipe search menggunakan “impure” pipe. Penjelasan mengenai impure pipe ini dapat anda lihat pada ulasan chapter-6 mengapa kita menggunakan impure pipe untuk search maupun sort namun secara singkatnya adalah karena data pada pipe tersebut berubah tidak pada saat proses inisiasi / ngOnInit().

berikut ini adalah kode untuk com-listnote.component.ts untuk mengakomodasi proses pada “form” select (menggunakan ngModel). SortOPtion untuk menyimpan daftar opsi dalam bentuk array object untuk nilai ngModel disimpan pada searchTypeValue dengan nilai default ‘asc’ dan bertipe string.

import { Component, OnInit } from '@angular/core';
import { ServiceNoteService } from './../service-note.service';
import { NoteModel } from './../note-model';
// angular material
import {MdSnackBar} from '@angular/material';

@Component({
  selector: 'app-com-listnote',
  templateUrl: './com-listnote.component.html',
  styleUrls: ['./com-listnote.component.css'],
})
export class ComListnoteComponent implements OnInit {

  listNote : Array<NoteModel>;
  searchQuery = "";
  onSearchLoading = false;
  searchTypeValue: string = 'asc';

  sortOption = [
    {value: 'asc', viewValue: 'ascending'},
    {value: 'desc', viewValue: 'descending'},
  ];

  constructor(
    public serviceNoteService : ServiceNoteService,
    private snackBar : MdSnackBar
  ) { }

  openSnackBar() {
     this.snackBar.open('note telah dihapus', 'sukses', {
      duration: 2000,
    });
  }

  doSearch(value){
    // set serachQuery property
    this.searchQuery = value;
  }

  onLoadingChange(value){
    this.onSearchLoading = value;
  }
  
  ngOnInit() {
    this.listNote = this.serviceNoteService.getNote();
  }

  onDeleteNote(note : NoteModel){
    this.serviceNoteService.deleteNote(note);
    this.openSnackBar();
  }

}

done. Sangat sederhana sekali membuat sort pipe dan chain terhadap pipe search.