13 mar 2017
5 min

ANGULAR 2 TIPS & TRICKS cz. I

Heja! Angular Tips & Tricks będzie nową serią artykułów, w których będę pokazywał drobne rzeczy, porady, dobre praktyki, tricki, które będą dość krótkie, więc same w sobie nie zasługują na osobne artykuły. No to zaczynamy ; )

1. Struktura SharedModule

Zapewne stosowanie SharedModule (moduł dla komponentów współdzielonych w całej aplikacji, które mają wiele instancji, np. modale, taby etc.) i CoreModule (moduł dla komponentów, które mają jedną instancję dla całej aplikacji, np. login / sidebar)  jest Ci znane. Jak poprawnie trzymać nasze komponenty w SharedModuleJeśli trzymasz je jak poniżej:

To możesz to zrobić lepiej:

Różnica jest oczywista. Nie duplikujemy nazw komponentów, moduł jest czytelniejszy i łatwiejszy w utrzymaniu, bo tylko raz deklarujemy nazwę. Już przy około 45 komponentach, sharedModule w wariancie II ma około 40% mniej objętości kodu niż w wersji 1.

2. Rozbudowana dyrektywa ngClass

Dyrektywa ngClass jest bardzo przydatna. O ile opiera się na 1 klasie, np:

<div [ngClass]="{'tab-active': isTabActive}">Settings</div>

To jest jak najbardziej w porządku. Ale jak dochodzimy do bardziej rozbudowanych wariantów, np.

<div [ngClass]="{'active-tab': isTabActive && isTabInView, 'submenu': isSubMenu, 'multi-tab': isMultiTab }">Settings</div>

To wiedz, że dzieje się źle! Zaśmiecamy templatkę i wynosimy zbyt dużo logiki do widoku. Lepiej zrobić to w następujący sposób:

  • w klasie komponentu tworzymy gettera:
get getCssClassesForTab() : void {
  return {
    'active-tab': this.isTabActive && this.isTabInView,
    'submenu': this.isSubMenu,
    'multi-tab': this.isMultiTab
  };
}
  • i na widoku wyłącznie:
<div [ngClass]="getCssClassesForTab">Settings</div>

Podobny patent polecam dla rozbudowanych dyrektyw ngStyle.

3. Kolejność deklaracji dyrektyw ma znaczenie

Wyobraźmy sobie przykład, że jedna dyrektywa korzysta z atrybutów, nadanych przez inną dyrektywę na tym samym elemencie, np:

<p directiveOne directiveTwo>Hello World</p>

DirectiveTwo nadaje elementowi atrybut X, a dyrektywa DirectiveOne korzysta między innymi z atrybutu X do zrobienia czegoś tam innego. DirectiveOne będzie mieć dostęp do atrybutu X, pod warunkiem, że directiveTwo została wcześniej zadeklarowana w module w tablicy declarations, tzn:

declarations: [ DirectiveTwo, DirectiveOne ];

Kolejność ich wypisania w tagu HTML nie ma znaczenia! Jeśli dyrektywy są zadeklarowane w osobnych modułach (DirectiveOne w ModuleOne, a DirectiveTwo w ModuleTwo),  to znaczenie ma kolejność importów modułów:

imports: [ModuleTwo, ModuleOne].

Dobrze to wiedzieć, ponieważ Angular nie zwróci Ci błędu. Twoja dyrektywa po prostu otrzyma undefined na danym atrybucie / wartości pobranym z innej dyrektywy.

4. Atrybut Style i jednostki

Jeśli używasz dyrektywy style wraz  z procentami w ten sposób:

<div [style.width]="someValue + '%'">Hey!</div>

To lepszym rozwiązaniem jest przeniesienie procentów do dyrektywy, tzn:

<div [style.width.%]="someValue">Hey!</div>

Podobnie możesz robić ze wszystkimi jednostkami (np.  em, px, rem etc).

5. Wyświetlenie komponentu-dziecka, dopiero jak otrzyma dane

W aplikacjach opartych o komponenty sporo korzystamy z zagnieżdżonych komponentów. Jeśli komponent rodzic przekazuje do komponentu dziecka dane asynchroniczne, to musimy w jakiś sposób powiedzieć Angularowi, aby dopiero załadował komponent dziecko, jak dane dostaną dostarczone (inaczej otrzymamy błąd). Możemy to zrobić w bardzo prosty sposób, z użyciem *ngIf, np:

<user-list [users]="users" *ngIf="users"></user-list>

Dzięki prostemu trickowi *ngIf, nasz komponent user-list poczeka z ukazaniem się na widoku, aż komponent-rodzic dostarczy mu listę userów.

6. Rekurencja na widoku

Potrzebujesz wyświetlić dane z pliku JSON, a nie wiesz ile będzie poziomów zagnieżdżenia tego samego typu obiektu? Nic nie stoi na przeszkodzie, aby w templatce komponentu, odnosić się do selektora tworzonego komponentu, tak samo jak w środku funkcji, możesz wołać nazwę tej funkcji w celu uzyskania rekurencji.

Przykładowo masz pliki JSON z drzewami genealogicznymi, każde dziecko ma swoje dzieci, ale dostajemy rodziny z różną ilością pokoleń. Możemy załatwić to następująco:

@Component({
 selector: 'children',
 template: `
 <div *ngFor="let child of children">
   <ul>
     <li>
     {{child.name}}
     <children [children]="child.children" *ngIf="child.children"></children>
     </li>
   </ul>
 </div>
 `,
})

export class ChildrenComponent {
 @Input() children;
}

Czyli w templatce komponentu Children wołamy komponent Children.

Plunker do powyższego przykładu:

LIVE EXAMPLE

Między innymi w oficjalnym tutorialu Angulara spotykamy się z metodą navigate() klasy Router, która może wyglądać następująco:

 gotoDetail() {
   this.router.navigate(['/detail', this.selectedHero.id]);
 }

Co ciekawe, metoda navigate zwraca nam Promise<boolean>, dzięki temu po zakończeniu nawigacji, możemy wywołać inną funkcję, umieszczoną w .then(), (np. pokazać tosta):

 gotoDetail() {
   this.router.navigate(['/detail', this.selectedHero.id]).then((data) => {
     console.log(data, 'promise resolved')
   });
 }

Argument data w powyższej funkcji, przyjmuje wartość true (promise resolved) lub false (promise rejected).

To by było na tyle dzisiaj! Co jakiś czas będę wrzucać zebrane złote myśli 🙂

Podziel się artykułem

Zapisz się na nasz newsletter

Dołącz do community Angular.love i bądź na bieżąco z trendami.