#angular #typescript
#angular #typescript
Вопрос:
Я пытаюсь добавить Google Analytics в свое приложение Angular без необходимости вручную добавлять скрипты в индексный файл. Моя цель — использовать сервис, в котором есть функции, которые вы можете вызывать для инициализации аналитики и отслеживания просмотров страниц. Вот основная часть сервиса:
export class GoogleAnalyticsService {
private googleAnalyticsId: string;
private renderer2: Renderer2;
private scriptsLoaded: boolean = false;
constructor(
private rendererFactory2: RendererFactory2,
@Inject(DOCUMENT) private _document: Document,
private _config: RuntimeConfigLoaderService,
private _router: Router,
) {
this.renderer2 = this.rendererFactory2.createRenderer(null, null);
this.googleAnalyticsId = this._config.getConfigObjectKey('googleAnalyticsId');
}
init() {
this.insertMainScript();
}
private insertMainScript() {
if (this.googleAnalyticsId) {
const script: HTMLScriptElement = this.renderer2.createElement('script');
script.type = 'text/javascript';
script.onload = this.insertSecondHalfOfScript.bind(this);
script.src = `https://www.googletagmanager.com/gtag/js?id=${this.googleAnalyticsId}`;
script.text = '';
this.renderer2.appendChild(this._document.body, script);
}
}
private insertSecondHalfOfScript() {
const script: HTMLScriptElement = this.renderer2.createElement('script');
script.type = 'text/javascript';
script.src = '';
script.text = `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
`;
this.renderer2.appendChild(this._document.body, script);
this.scriptsLoaded = true;
}
trackSinglePageView(event: NavigationEnd) {
if (this.googleAnalyticsId amp;amp; this.scriptsLoaded) {
console.log('logging pageview');
gtag('config', this.googleAnalyticsId, { page_path: event.urlAfterRedirects });
}
}
trackPageViews() {
return this._router.events.pipe(
filter((evt: RouterEvent) => evt instanceof NavigationEnd),
tap((event: NavigationEnd) => {
this.trackSinglePageView(event);
}),
);
}
}
Основной функцией, вызываемой из AppComponent
является init
. Это приведет к внедрению скриптов на страницу. Наблюдая за загрузкой приложения, я вижу, что эти скрипты добавляются. Я также вижу https://www.googletagmanager.com/gtag/js
загрузку скрипта на вкладке Сеть инструментов разработчика. Итак, скрипт определенно существует.
Затем после вызова init
функции в AppComponent
я вызываю trackPageViews
функцию и подписываюсь на возвращаемую наблюдаемую. Я отфильтровываю все события маршрутизатора до тех пор, пока не будут загружены вышеупомянутые сценарии, а затем отфильтровываю все события, которые не являются NavigationEnd
событиями. Если скрипты загружены и это событие NavigationEnd, то вызывается trackSinglePageView
функция and gtag
с необходимыми данными. Однако, когда это происходит, я получаю следующую ошибку:
core.js:6189 ERROR ReferenceError: gtag is not defined
at GoogleAnalyticsService.trackSinglePageView (google-analytics.service.ts:58)
at TapSubscriber._tapNext (google-analytics.service.ts:69)
at TapSubscriber._next (tap.js:40)
at TapSubscriber.next (Subscriber.js:49)
at FilterSubscriber._next (filter.js:33)
at FilterSubscriber.next (Subscriber.js:49)
at Subject.next (Subject.js:39)
at SafeSubscriber._next (router.js:7593)
at SafeSubscriber.__tryOrUnsub (Subscriber.js:183)
at SafeSubscriber.next (Subscriber.js:122)
Если я не использую сервис для загрузки сценариев аналитики и размещения их в head
приложении, index.html файл и просто отслеживайте просмотры страниц, тогда я не получаю никаких ошибок в консоли. Таким образом, похоже, что, хотя скрипты загружены, gtag
все еще не определено, если скрипты analytics не находятся в head
.
Есть ли какой-либо способ обойти это? Я делаю что-то здесь неправильно? Любые идеи приветствуются.
Комментарии:
1. попробуйте
(<any>window).gtag(...)
2. @MKhalidJunaid Спасибо за ответ. Ознакомьтесь с моим ответом ниже, чтобы увидеть, что в итоге сработало.
Ответ №1:
Я знаю, что мы реализовали gtag, создав отдельный индексный файл для dev vs prod.
Вы можете настроить angular.json для использования одного или другого
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"index": {
"input": "src/overrides/prod/index.prod.html",
"output": "index.html"
},
"dev": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
],
"index": {
"input": "src/overrides/qa/index.qa.html",
"output": "index.html"
},
Ответ №2:
Таким образом, получается, что текст скрипта, созданного в insertSecondHalfOfScript
функции, так и не был запущен. Похоже, что именно там gtag
делается доступным для страницы. Поэтому вместо добавления кода к этому текстовому атрибуту я поместил его в файл ресурсов и загрузил его так, как я загружаю скрипт в insertMainScript
функцию. Итак, поток инициализации теперь выглядит следующим образом:
init() {
this.insertMainScript();
}
private insertMainScript() {
if (this.googleAnalyticsId) {
const script: HTMLScriptElement = this.renderer2.createElement('script');
script.type = 'text/javascript';
script.onload = this.insertSecondHalfOfScript.bind(this);
script.src = `https://www.googletagmanager.com/gtag/js?id=${this.googleAnalyticsId}`;
script.text = '';
this.renderer2.appendChild(this._document.body, script);
}
}
private insertSecondHalfOfScript() {
const script: HTMLScriptElement = this.renderer2.createElement('script');
script.type = 'text/javascript';
script.src = '/assets/scripts/analytics/analytics-starting-script.js';
script.text = '';
this.renderer2.appendChild(this._document.body, script);
script.onload = () => {
this.scriptsLoaded = true;
};
}
Загрузка второго скрипта, подобного этому, кажется, работает, поскольку теперь я не получаю того, ReferenceError
что получал раньше.