[DajSięPoznać#3] Aurelia – prosty framework do MVVM

Wybór technologii

Z kilku powodów przy wypełnianiu zgłoszenia konkursowego zdecydowałem się na Aurelię jako framework do aplikacji SPA. Po pierwsze ze względu na autora (Rob Eisenberg) i bardzo pozytywne doświadczenia z WPF-a z jego wcześniejszym dziełem (Caliburn.Micro). Po drugie ze względu na bardzo zachęcającą prezentację na temat Aurelii na temat zeszłorocznego dotNet developer days w Warszawie. Po trzecie, żeby porównać pracę z Aurelią z dawnymi doświadczeniami z Angularem i Knockoutem. I po czwarte wreszcie, żeby poprogramować sobie w nowym, wzbogaconym o całkiem fajne rzeczy JavaScripcie (ES2015/ ES2016).

asdf

 

Pierwsze kroki

Na początek coś typowego dla technologii JS-owych, czyli wpisujemy kilka komend i zakłada nam się kilkaset plików. Dla Aurelii używam jspm jako menadżera pakietów, stąd wszystkie zależności wrzuci on sobie do folderu /jspm_packages/. Zatem zaczynamy od:

npm install jspm -g
jspm init
jspm install aurelia-framework
jspm install aurelia-bootstrapper

Aurelia jest zbudowana modułowo, a zatem kolejne pakiety można doinstalowywać sobie w miarę potrzeb.

Ostatni etap to podlinkowanie kluczowych skryptów oraz umieszczenie na body atrybutu aurelia-app, dzięki któremu framework nam się “zbootstrappuje”. Przez konwencję załadowany zostanie widok

<body aurelia-app>
    <script src="jspm_packages/system.js"></script>
    <script src="config.js"></script>
    <script>
        System.import("aurelia-bootstrapper")
    </script>
</body>

Router, nawigacja

Jak już wspomniałem, bootstrapper automatycznie załaduje nam plik app.html. Poprzez mechanizm nawigacji możemy podmieniać część takiej strony, zostawiając niezmienne górne menu czy logo.”Podmienialna” część widoku będzie reprezentowana przez element <router-view>. W app.js definiujemy podstrony jako routingi.

export class App{

    configureRouter(config, router) {
        config.title = 'Byteville - find your estate';
        config.map([
          { 
              route: ['','districts'], 
              name: 'districts', 
              moduleId: './Modules/districts', 
              nav: true, title:'Lista dzielnic' 
          },
          { 
              route: 'districts/:name', 
              name: 'districtDetails', 
              moduleId: './Modules/districtDetails', 
              nav: false 
          }
        ]);

        this.router = router;
    }   
}

 

Plik districts.js będzie ładował AJAX-owo listę dzielnic z serwera. Po doinstalowaniu dodatkowego pakietu jspm-em wstawiamy odpowiednią logikę do metody activate. Jest to specjalna metoda, którą framework zawoła przy ładowaniu widoku.

import {HttpClient} from "aurelia-http-client"

export class Districts{   
    activate(){
        var client = new HttpClient();
        var self = this;
        client.get("api/districts").then( response => {
            self.districts = response.content;
        })
    }
}

 

Z kolei w pliku z widokiem (districts.html) tworzymy odpowiednie bindingi i budujemy dynamicznie nawigację poprzez route-href.

<template>
    <div class="streets-list-container">
        <ul class="list-group" repeat.for="district of districts">
            <li class="list-group-item">
                <a class="reset-anchor" route-href="route: districtDetails; 
                                   params.bind: {name:district.name}">
                    <span>${district.name}</span>
                    <span class="badge float-right">${district.streetsCount}</span>
                </a>
            </li>
        </ul>
    </div>
</template>

Przykładowy href będzie wyglądał następująco: /#/districts/Bronowice. Do parametru URL mamy dostęp w kolejnym ViewModelu jako argument metody activate.

activate(params){
    this.name = params.name;
    var client = new HttpClient();
    var self = this;
    client.get("api/districts/" + params.name).then( response => {
        self.streets = response.content;
    })
}

 

Wyszukiwarka z throttlingiem i spinnerem

W poprzednim poscie opisane zostało, jak zaimplementować wyszukiwarkę po stronie serwera. Tym razem zostanie zbudowana dla niej kontrolka UI-owa.

Na początku myślałem, że throttling będzie trzeba zrobić samemu, ale okazało się, że Aurelia daje go jako Binding Behavior.  Wystarczy dopisać przy definicji bindingu throttle i ilość milisekund. Dzięki temu property VIewModelu będzie aktualizowane z opóźnieniem, a zmiany pojawią się dopiero po 500 ms od ostatniej modyfikacji – jeśli będziemy szybko pisali w polu tekstowym, to zmiany nie będą aktualizowane po każdej literce. Dzięki temu ograniczymy liczbę requestów do serwera. Widok kontrolki wygląda następująco:

<template>
    <div class="streets-list-container">
        <input type="text" class="form-control" placeholder="Podaj nazwę ulicy, osiedla..."
               autofocues value.bind="text & throttle:500" />
    </div>
    <div class="streets-list-container">
        <div show.bind="isSearching" class="container">
            <i class="fa fa-spinner fa-pulse"></i>
        </div>
        <ul class="list-group" repeat.for="result of results">
            <li class="list-group-item">${result.name} (<b>${result.district})</b></li>
        </ul>
    </div>
</template>

Dzięki temu możemy zasubskrybować się na zmiany propercji ViewModelu i wyszukiwać wpisaną frazę na serwerze. Property isSearching binduje widoczność spinnera.

import {HttpClient} from "aurelia-http-client"
import {ObserverLocator} from 'aurelia-framework';

export class StreetsSearch {
    
    constructor() {
        this.text = "";
        this.results = [];
        this.observerLocator = new ObserverLocator();  
        this.isSearching = false;
    }

    bind(){
        let self = this;
        let client = new HttpClient();
        this.observerLocator.getObserver(this, 'text').subscribe(function executeSearch(val){
            self.isSearching = true;
            self.results = [];
            client.get("api/search?q=" + val).then(response => {                
                setTimeout(function(){ 
                    self.isSearching = false;
                    self.results = response.content;
                }, 1000);                
            })
        });
    }
}
Advertisements

One thought on “[DajSięPoznać#3] Aurelia – prosty framework do MVVM

  1. Pingback: [DajSięPoznać] Podsumowanie | When the smoke is going down

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s