Angular и Google Analytics

#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 что получал раньше.