ngx-google-analytics icon indicating copy to clipboard operation
ngx-google-analytics copied to clipboard

If I use the above method, I am getting the below error on page load -

Open aman-koco opened this issue 4 years ago • 10 comments

If I use the above method, I am getting the below error on page load - Empty tracking code for Google Analytics. Make sure to provide one when initializing NgxGoogleAnalyticsModule.

In the environment files for which I do not want to have GA, I have entered as blank i.e GA: '' Any idea how to resolve the error?

Originally posted by @aman-koco in https://github.com/maxandriani/ngx-google-analytics/issues/37#issuecomment-775147121

aman-koco avatar Feb 08 '21 13:02 aman-koco

I solved the conditional initialization issue by creating an AnalyticsService to manage ngx-google-analytics configuration after application bootstrap, per the recommendation on #37 and the coding hints on #40, combined with some searching on how to get a ComponentRef to the bootstrap component:

analytics.service.ts

import { ComponentRef, Inject, Injectable } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { GoogleAnalyticsInitializer, GoogleAnalyticsRouterInitializer, GoogleAnalyticsService, GtagFn, NGX_GOOGLE_ANALYTICS_SETTINGS_TOKEN, NGX_GTAG_FN } from 'ngx-google-analytics';
import { IGoogleAnalyticsSettings } from 'ngx-google-analytics/lib/interfaces/i-google-analytics-settings';

import { environment } from '../environments/environment';


@Injectable({providedIn: 'root'})
export class AnalyticsService {
  private isInitialized: boolean;

  public constructor(
    @Inject(NGX_GOOGLE_ANALYTICS_SETTINGS_TOKEN) private googleAnalyticsSettingsToken: IGoogleAnalyticsSettings,
    @Inject(NGX_GTAG_FN) private googleTagFunction: GtagFn,
    @Inject(DOCUMENT) private document: Document,
    public googleAnalyticsService: GoogleAnalyticsService,
  ) {
  }

  public initializeGoogleAnalytics(bootstrapComponent: ComponentRef<unknown>) {
    if (environment.production && !this.isInitialized) {
      Promise.all([
        GoogleAnalyticsInitializer(this.googleAnalyticsSettingsToken, this.googleTagFunction, document)(),
        GoogleAnalyticsRouterInitializer({}, this.googleAnalyticsService)(bootstrapComponent),
      ]).then(() => {
        this.isInitialized = true;
      }).catch((error: any) => {
        this.isInitialized = false;
      });
    }
  }
}

app.module.ts:

import { APP_BOOTSTRAP_LISTENER, ComponentRef, NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { NGX_GOOGLE_ANALYTICS_SETTINGS_TOKEN } from 'ngx-google-analytics';


import { environment } from './core/environments/environment';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { AnalyticsService } from './core/services/analytics.service';


@NgModule({
  // Providers: Services and Values available to the Angular dependency injector
  providers: [
    {
      provide: NGX_GOOGLE_ANALYTICS_SETTINGS_TOKEN,
      useValue: {
        trackingCode: environment.GoogleAnalyticsCode,
      },
    },
    {
      provide: APP_BOOTSTRAP_LISTENER,
      multi: true,
      useFactory: (analyticsService: AnalyticsService) => {
        return (component: ComponentRef<unknown>) => {
          analyticsService.initializeGoogleAnalytics(component);
        };
      },
      deps: [AnalyticsService],
    },
  ],
  // Declarations: Components, Pipes, Directives belonging to this module & thereby available to others in this module
  declarations: [
    AppComponent,
  ],
  // Imports: Other Modules whose Declarations should be available to components in this module
  imports: [
    // …
    BrowserModule,
    AppRoutingModule,
  ],
  // Bootstrap: initial component to load when initializing application
  bootstrap: [AppComponent],
})
/** Angular root module */
export class AppModule {
  public constructor(
  ) {
  }
}

KeithGillette avatar Mar 23 '21 20:03 KeithGillette

@KeithGillette The only down side is you can not make any call to GoogleAnalyticsService before call the initialize functions :/ Currently I have no time to make new features on this lib because I've applied to a Certification Program and I also have a full-time job.

I think your guys could implement a hidden property on ConfigurationToken w/ a Subject<'initialized'|'consent'|'initialize'>(); And then refactory GoogleAnalyticsService and initialization functions to listen this observable.

The GoogleAnalyticsService should also stack the commands if ga is not initialized and than call all stacked commands.

maxandriani avatar Mar 23 '21 22:03 maxandriani

Yes, @maxandriani, I realized that limitation, so in my application, I added methods to the AnalyticsService from my previous reply that proxy the GoogleAnalytics.event and GoogleAnalytics.exception methods that I want to use, but guard against calls if (!this.isInitialized).

The ngx-google-analytics library refactoring you describe makes sense and would be a great enhancement to easily enable delayed initialization for the multiple use cases of disabling outside of production, getting user consent, and perhaps also including an app-generated userId for authenticated sessions, which is something I'm trying to figure out how to do now …

KeithGillette avatar Mar 24 '21 00:03 KeithGillette

I'm trying this code but it doesn't detect the change of routes. The Analytics dashboard only shows the first page and no longer updates. Can you help me?

alexsanderluisdev avatar Aug 02 '21 20:08 alexsanderluisdev

@KeithGillette did you figure out how to set userId?

andriipaziuk avatar Dec 11 '21 18:12 andriipaziuk

@andriipaziuk — Not in any automated way. I am only logging sign_up & login GA actions via the proxied event method (described in my previous reply), which is called in the response handlers for the methods that invoke our application's UserRegister and UserSignIn mutations, both of which return a user object containing an id, so those calls pass in User as category and the user id as label.

KeithGillette avatar Dec 11 '21 18:12 KeithGillette

@KeithGillette how do you call the initializeGoogleAnalytics method of AnalyticsService then?

xCryzed avatar Mar 18 '22 10:03 xCryzed

@xCryzed — The code sample in my original reply to this thread shows how initializeGoogleAnalytics is called in the AppModule provider creation.

KeithGillette avatar Mar 18 '22 10:03 KeithGillette

@KeithGillette yes but what if I want to initialize it only when the user consent to the cookies?

xCryzed avatar Mar 18 '22 11:03 xCryzed

@xCryzed — Does issue #40 referenced in my original reply address your question?

KeithGillette avatar Mar 18 '22 11:03 KeithGillette