开发者问题收集

Angular 和 Google Analytics

2020-08-21
814

我试图将 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 && 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 脚本加载在开发人员工具的“网络”选项卡中。所以脚本肯定在那里。

然后在 AppComponent 中调用 init 函数后,我调用 trackPageViews 函数并订阅返回的 Observable。我过滤掉所有路由器事件,直到上述脚本加载完毕,然后过滤掉所有非 NavigationEnd 事件。如果脚本已加载并且是 NavigationEnd 事件,则使用必要数据调用 trackSinglePageView 函数和 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)

如果我不使用该服务加载分析脚本并将其放在应用程序 index.html 文件的 head 中,而只是跟踪页面浏览量,那么控制台中不会出现任何错误。因此,似乎尽管脚本已加载,但除非分析脚本位于 head 中,否则 gtag 仍未定义。

有什么办法可以解决这个问题?我在这里做错了什么吗?任何想法都非常感谢。

2个回答

我知道我们通过为 dev 和 prod 设置单独的索引文件来实现 gtag。

您可以将 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"
          },
iamaword
2020-08-21

事实证明,在 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

pjlamb12
2020-08-21