В първата част на тази публикация, дискусията беше фокусирана основно около различните способи за динамичен 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, за действията на потребителя.
Вижда се от горния екран, че:
- Скрипта analytics.js се download-вa от браузера
- При преход от страница в страница и при натискане на бутона се post-ват данни към collect адреса на Google Analytics.
Заключение
В тези два поста се опитах да разгледам и опиша с думи и примери три различни подхода, за постигане на целите и при двете теми:
- Download на third-party JavaScript библиотека в Angular приложение
- „Закачане“ за инициализирането на Angular приложение
Надявам се не ви е било скучно и че ще ви е от полза, ако ви се налага да програмирате подобни неща, да изберете подход, който да ви служи най-добре.
Автор: Александър Гьонов