Struktura aplikacji

Aplikację Angulara tworzymy w Typescript. Klasy TypeScript mogą reprezentować różne elementy aplikacji - zależnie od użytych dekoratorów:

  • Dekorator @NgModule tworzy moduł
  • Dekorator @Component tworzy komponent (zawiera m.in. właściwość template opisującą fragment HTML, który ma być renderowany przez przeglądarkę)
  • Dekorator @Injectable pozwala na obsługę modułu przez system wstrzykiwania zależności (DI)..

źródło rysunku: Jakob Fain, Anton Moiseev, "Angular 2. Programowanie z TypeScript".

Struktura plików

Aby rozpocząć, utwórzmy aplikację Angulara z pojedynczym komponentem. Aby to zrobić, potrzebujemy następujących plików:

  • app/app.component.ts - tutaj definiujemy nasz główny komponent,
  • app/app.module.ts - strktura modułu (app) - określa użyte komponenty, potoki i usługi,
  • index.html - jest to strona, na której będzie renderowany komponent
  • main.ts - główny plik uruchomieniowy - łączący komponent ze stroną, zależy od platformy

app/app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: '<b>Pierwsza aplikacja Angular!</b>'
})
export class AppComponent {
}
  • index.html
<body>
    <app-root>Loading...</app-root>
</body>
  • app/app.module.ts
import { BrowserModule }  from '@angular/platform-browser';  
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component'

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {
}
  • app/main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.log(err));

Zobacz przykład [001]

Komponenty umieszczamy a podkatalogu src (każdy komponent w odrębnym katalogu). Prócz nich katalog src powinien zawierać pliki:

  • index.html - główny plik aplikacji ze znacznikiem wskazującym miejsce renderowania głównego komponentu (zwyczajowo <app-root></app-root>.
  • main.ts - moduł ładowania aplikacji, dostosowany do środowiska na którym ona działa
  • polyfills.ts - dodatkowe biblioteki, które zapewniają obsługę użytych funkcji w starszych wersjach przeglądarek WWW.
  • styles.css - główny plik z arkuszem styli (może być pusty)

Główny katalog aplikacji poza wspomnianym katalogiem src zawiera:

  • tsconfig.json - konfiguracja TypeScript; dodatkowo dla każdego modułu mogą być tworzone pliki dziedziczące ten główny plik - w katalogu src o nazwach tsconfig.[nazwa_modułu].json
  • angular.json - konfiguracja Angulara
  • package.json - plik zarządzania pakietami NodeJS (npm lub yarn)

Zazwyczaj aplikacje tworzymy przy użyciu programu ng (ng new ... - zobacz rozdział Angular CLI). Nic jednak nie stoi na przeszkodzie, by stworzyć pliki aplikacji w inny sposób. Jedną z takich minimalistycznych propozycji znajdziesz w katalogu (bez plików związanych z testami): https://github.com/tenarjw/ng_intro_by_example/tree/master/min

Proces ładowania (bootstrap) rozpoczyna się od skryptu main.ts , który jest głównym punktem wejścia aplikacji. Deklaruje się w nim moduł główny aplikacji - nazywany zazwyczaj AppModule. W tym module dopiero jest skonfigurowany komponen ( AppComponent ), który powinien wyrenderować aplikację (z selektorem app-root). Dlatego umieszcza się jego nazwę we własności bootstrap wspomnianego wyżej głównego modułu. Jest on renderowany na każdym napotkanym elemencie HTMLapp-root. Dlatego w pliku index.html umieszczamy element app-root.

Plik _ app/main.ts _zawiera użycie funkcji platformBrowserDynamic().BootstrapModule(AppModule) do uruchomienia procesu ładowania.

Dlaczego Angular uruchamia się w ten sposób? Ponieważ Angular nie jest strukturą opartą wyłącznie w internecie, możemy napisać komponenty, które będą działać w NativeScript lub Cordova, lub dowolnym innym środowisku, które może obsługiwać aplikacje Angular. Wtedy w procesie ładowania możemy zaimportować platformę, z której chcielibyśmy korzystać, w zależności od środowiska, w którym działamy. W naszym przykładzie, ponieważ tworzymy aplikację Angular w przeglądarce, użyliśmy procesu ładowania znajdującego się w @angle/platform-browser-dynamic.

Pozostawienie procesu ładowania w oddzielnym pliku _ main.ts _jest zdecydowanie bardzo dobrym pomysłem. Ułatwia to testowanie (ponieważ komponenty są odizolowane od wywołania bootstrap), łatwiej je ponownie wykorzystać. Zapewnia to lepszą organizację i strukturę naszej aplikacji.

W większości przykładów dołączonych do niniejszego podręcznika, zawarto jedynie pliki modułów. Można je umieścić w dowolnej aplikacji testowej (np. utworzonej komendą ng new).

Usługi

Pojęcie "usługi" jest dość ogólne - określa się nim zazwyczaj klasą o wąskim, dobrze zdefiniowanym celu (robi coś konkretnego). Niemniej rozróżnienie usług i komponentów jest dla Angulara ważne (https://angular.io/guide/architecture-services\ - zwłaszcza gdy stosujemy "wstrzykiwanie zależności" (zostanie to omówione w odrębnym rozdziale).

Ponieważ proces ładowania początkowego uwzględnia również wspomniany system zależności - poza zadeklarowaniem wykorzystywanych komponentów (właściwość declarations) musimy wskazać "dostawców usług" (własność providers). Poniższy przykład modułu pokazuje rejestrowanie jako usługi komponentu o nazwie GreeterService.

app/app.module.ts

import { Component, OnInit } from '@angular/core';
import { GreeterService } from './greeter.service';

@Component({
  selector: 'app-root',
  template: '<b>{{greeting}}</b>'
})
export class AppComponent implements OnInit {
  public greeting ='';

  constructor(private greeterService: GreeterService) { }

  ngOnInit() {
    this.greeting = this.greeterService.getMessage();
  }
}

Zobacz przykład [002]