В първата част на тази публикация, дискусията беше фокусирана основно около различните способи за динамичен download на third-party JavaScript библиотеки в едно Angular приложение. Тук в този втори пост, ще се обсъждат начините, по които може да се „закачим“ за инициализирането на Angular приложение и да изпълняваме наша програмна логика. За илюстрация ще продължа да използвам примерното приложение от първата част, което отново ще цитирам на няколко места в постта.

Кода на примерното приложение е достъпен на: https://github.com/agyonov/NgInitGA

Самото приложение е живо на: https://agyonov.github.io/NgInitGA

За онези, които не са чели първата част или са я забравили, примера е с използване на Google Analytics и за да е по-смислен е разширен да позволява да се ползва и за пълно проследяване действията на потребителите в Angular приложение.

NB: Що се касае до track-не на потребители в Angular приложение, то има чудесни, готови библиотеки, като angulartics2, които можете да ползвате. Тук въпроса не е да създавам поредната такава библиотека, а с пример да покажа възможно решение на двата въпроса зададени в началото на този пост!

„Закачане“ за инициализирането на Angular приложение

Открил съм няколко способа да изпълните ваша програмна логика (ваш скрипт) при стартирането на Angular приложението в браузера. Ще изброя тук на кратко два от тях, а третия ще разгледам малко по-подробно.

1. Използване на „forRoot“ статичен метод

Ако имате сервиз, в обособен Angular „feature“ модул, то може би най-добрия и най-установен способ е да използвате статичен „forRoot“ метод. Метода се извиква при импортирането на вашия модул в главния модул на Angular приложението, в което използвате “feature“ модула и сервиза, който “feature“ модула предоставя.

Може да прочетете по-подробно на:

https://angular.io/guide/singleton-services#forroot

When to use Angular’s forRoot() method

2. Извикване на вашия скрипт в ngOnInit метода на главния AppComponent

Най-директния и не сложен способ е да изпълните скрипта в ngOnInit метода на главния AppComponent във вашето Angular приложение. Ако ви върши работа – прилагайте го. Ако използваме примера от първата част на публикацията, то там завършихме с един метод – „loadScript“. Този метод трябва да се извика, за да стартира download-а на third-party .js библиотеката на Google Analytics. В кода на app.component.ts това би изглеждало по следния начин:

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit {

  title = 'NgInit';

  constructor(private gas: GoogleAnalyticsService) {
  }

  ngOnInit(): void {
    // Start down load of JS Library
    this.gas.loadScript();
  }
}

В конкретното, примерно приложение и използването на Google Analytics за илюстрация, този похват ще сработи без каквито и да е проблеми.

Съображение срещу евентуалното му използване в други случаи, е че би имало ситуации, при които не би вършил работа ☹. Това са случаите, когато цялата инициализираща логика трябва да е завършила своето изпълнение преди стартирането на изпълнението на метода ngOnInit или какъвто и да било код от вашето приложение.

Пример, за такава ситуация е да речем когато имате задължителна автентикация на потребителя и тя трябва да е завършила, успешно или не, преди да се изпълнява какъвто и да е било друг код от вашето Angular приложение.

Това с автентикацията на потребителите в Angular приложение е интересна тема, за която може да напиша отделна публикация в бъдеще.

3. Използване на предефинирани token-и в Angular (най-интересно)

Има един способ да се „закачите“ за инициализиращия процес на Angular приложение, за който, според мен, информацията от Angular екипа е споделена по прекалено „скромен“ начин. Това са така наречените предефинирани token-ни и „factory providers“-ри. Информация за тях може да бъде намерена тук и тук.

В примерното приложение този подход е реализиран във файла app.module.ts, главния модул на Angular приложението.

В началото дефинираме „factory“ функцията GoogleAnalyticsServiceFactory и я експортираме! Последното е важно от гледна точка на TypeScript и АОТ компилирането на Angular приложението.

Самата функция трябва да връща друга, вътрешна функция. Нали затова е „factory“ 😊.

Вътрешната функция, която се връща от GoogleAnalyticsServiceFactory, е вашия код, който ще се изпълни при инициализирането на Angular приложението. Вътрешната функцията, може да връща за резултат void или Promise.

Внимание: Ако връща Promise, Angular приложението, ще бъде блокирано докато Promise-a не бъде изпълнен (resolven-ат)!

Вътрешната функция получава като входен параметър (чрез dependency-injection) сервиза GoogleAnalyticsService и изпълнява метода „loadScript“. Това и целяхме.

// Factory provider 
//for Angular. Provides function to be executed on Angular application startup export const GoogleAnalyticsServiceFactory = (gas: GoogleAnalyticsService) => { return () => { // download gas.loadScript(); }; }; @NgModule({ declarations: [ AppComponent, SecondPageComponent, HomeComponent ], imports: [ BrowserModule, AppRoutingModule ], providers: [ // Provides function to be executed on Angular application startup { provide: APP_INITIALIZER, useFactory: GoogleAnalyticsServiceFactory, deps: [GoogleAnalyticsService], multi: true } ], bootstrap: [AppComponent] }) export class AppModule { }

 

В масива providers, при дефинирането на главния модул AppModule на Angular приложението, образно казано “закачаме” функцията дефинирана по-горе, към стартиращия процес на Angular.

Това става с помощта на предефинирания tokenAPP_INITIALIZER. Той указва всички provider-и маркирани с него да се изпълнят преди Angular приложението да се инициализира!

Забележете, че като dependency (масива deps: [GoogleAnalyticsService]) са изброени параметрите, които Angular bootstrap процеса трябва да инстанцира и да подаде като параметри на функцията, която ще се изпълнява при стартирането на приложението!

И готово! Този път наистина 😊.

Примерното приложение

За достоверност, че горния код работи, може да се види примерното приложение на живо. Пробвайте го!

Към горните извадки код са добавени и тези към GoogleAnalyticsService сервиза за връзка с Google Analytics:

// Send page view event to Google Analytics
  public send(pageUrl: string): void {
    // Send
    window.ga('set', 'page', pageUrl);
    window.ga('send', 'pageview');
  }

  // Send event tracking event to Google Analytics
  public event(eventCategory: string, eventAction: string): void {
    // Send
    window.ga('send', 'event', eventCategory, eventAction);
  }

Тези методи следват инструкциите на Google Analytics, за работа при SPA приложения.

Методите се използват от страниците Home, Second Page и бутона Just an Event за да изпращат информация към Google Analytics, за действията на потребителя.

1

Вижда се от горния екран, че:

  1. Скрипта analytics.js се download-вa от браузера
  2. При преход от страница в страница и при натискане на бутона се post-ват данни към collect адреса на Google Analytics.

Заключение

В тези два поста се опитах да разгледам и опиша с думи и примери три различни подхода, за постигане на целите и при двете теми:

  • Download на third-party JavaScript библиотека в Angular приложение
  • „Закачане“ за инициализирането на Angular приложение

Надявам се не ви е било скучно и че ще ви е от полза, ако ви се налага да програмирате подобни неща, да изберете подход, който да ви служи най-добре.

Автор: Александър Гьонов