Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot find name 'gtag' #1

Closed
sagarp4412 opened this issue May 19, 2023 · 5 comments
Closed

Cannot find name 'gtag' #1

sagarp4412 opened this issue May 19, 2023 · 5 comments
Assignees
Labels
bug Something isn't working

Comments

@sagarp4412
Copy link

Your code Is working perfectly. But when we are making a build through this command "npm run build && npm run serve:ssr"
We are facing an error. Please have a look at this screenshot:

Screenshot from 2023-05-19 13-02-39

@ultimateakash ultimateakash self-assigned this May 19, 2023
@ultimateakash
Copy link
Owner

ultimateakash commented May 19, 2023

Hello, @sagarp4412, you are trying to generate SSR build. there is a simple solution.

  1. Remove the script tag and gtag code from index.html
  2. Update app.component.ts
  3. Update server.ts

app.component.ts

import { DOCUMENT, isPlatformBrowser } from '@angular/common';
import { Component, Inject, PLATFORM_ID, Renderer2 } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute, NavigationEnd, Router, RouterState } from '@angular/router';
declare let gtag: Function;

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  constructor(
    private router: Router,
    private renderer: Renderer2,
    private titleService: Title,
    @Inject(DOCUMENT) private document: Document,
    @Inject(PLATFORM_ID) private platformId: Object
  ) {
    if (isPlatformBrowser(this.platformId)) {
      this.injectScripts();
    }
    this.handleRouteEvents();
  }

  injectScripts() {
    const script = this.renderer.createElement('script');
    script.type = 'text/javascript';
    script.src = 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX';
    this.renderer.appendChild(this.document.body, script);

    const scriptBody = this.renderer.createElement('script');
    scriptBody.type = 'text/javascript';
    scriptBody.text = `
      window.dataLayer = window.dataLayer || [];
      function gtag() { dataLayer.push(arguments); }
      gtag('js', new Date());

      gtag('config', 'G-XXXXXXXXXX');
    `;
    this.renderer.appendChild(this.document.body, scriptBody);
  }

  handleRouteEvents() {
    this.router.events.subscribe(event => {
      if (event instanceof NavigationEnd) {
        const title = this.getTitle(this.router.routerState, this.router.routerState.root).join('-');
        this.titleService.setTitle(title);
        gtag('event', 'page_view', {
          page_title: title,
          page_path: event.urlAfterRedirects,
          page_location: this.document.location.href
        })
      }
    });
  }

  getTitle(state: RouterState, parent: ActivatedRoute): string[] {
    const data = [];
    if (parent && parent.snapshot.data && parent.snapshot.data['title']) {
      data.push(parent.snapshot.data['title']);
    }
    if (state && parent && parent.firstChild) {
      data.push(...this.getTitle(state, parent.firstChild));
    }
    return data;
  }
}

server.ts

import 'zone.js/node';

import { APP_BASE_HREF } from '@angular/common';
import { ngExpressEngine } from '@nguniversal/express-engine';
import * as express from 'express';
import { existsSync } from 'fs';
import { join } from 'path';

import { AppServerModule } from './src/main.server';
// @ts-ignore
global.window = {};
// @ts-ignore
global.gtag = () => {};
// The Express app is exported so that it can be used by serverless Functions.
export function app(): express.Express {
  const server = express();
  const distFolder = join(process.cwd(), 'dist/browser');
  const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';

  // Our Universal express-engine (found @ https://github.com/angular/universal/tree/main/modules/express-engine)
  server.engine('html', ngExpressEngine({
    bootstrap: AppServerModule,
  }));

  server.set('view engine', 'html');
  server.set('views', distFolder);

  // TODO: implement data requests securely
  server.get('/api/**', (req, res) => {
    res.status(404).send('data requests are not yet supported');
  });

  // Serve static files from /browser
  server.get('*.*', express.static(distFolder, {
    maxAge: '1y'
  }));

  // All regular routes use the Universal engine
  server.get('*', (req, res) => {
    res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
  });

  return server;
}

function run(): void {
  const port = process.env['PORT'] || 4000;

  // Start up the Node server
  const server = app();
  server.listen(port, () => {
    console.log(`Node Express server listening on http://localhost:${port}`);
  });
}

// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
  run();
}

export * from './src/main.server';

I have not tested the above changes. you can try and let me know.
Thanks.

@sagarp4412
Copy link
Author

sagarp4412 commented May 19, 2023

Hello Akash,

Thanks for the quick reply. I've updated the code as per your suggestion but still, I'm getting the same error.
I've already Implemented gatg In my project and it's working but as I've researched and I saw your one Is short and simple.
So, I tried and it's working but the problem with SSR.

Please have a look at this solution which I'm currently dealing with: (Without any npm packages)

index.html file

<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXX"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag('js', new Date());

    `gtag('config', 'G-XXXXX');`

</script>

app.component.ts file

let googleAnalyticsLastScript = document.createElement('script');
googleAnalyticsLastScript.innerHTML = 'gtag("event", "conversion", {"send_to": "XXXXXXX","value": "1.0", "currency": "ZAR"});';
head.insertBefore(googleAnalyticsLastScript, head.lastChild);

This one Is working but I don't want this 2-3 line code. That's why I'm looking for another solution.

@ultimateakash
Copy link
Owner

@sagarp4412 I will check and update you.

@ultimateakash
Copy link
Owner

ultimateakash commented May 20, 2023

Hello @sagarp4412, I have updated my answer. You need to make two changes.

  1. Define gtag function in app.component.ts
declare let gtag: Function;
  1. Add two global functions in server.ts
// @ts-ignore
global.window = {};
// @ts-ignore
global.gtag = () => {};

I have already tested the implementation. You can check my last comment for the full code.
Thanks

@ultimateakash ultimateakash added question Further information is requested bug Something isn't working and removed question Further information is requested labels May 20, 2023
@sagarp4412
Copy link
Author

Hello @ultimateakash

It's working. Thank you 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants