Search code examples
angulartypescriptangular8pendo

How to Implement Pendo in Angular 8+


I am attempting to set up Pendo in my Angular 8 application. However, their documentation seems to be off. The example scripts don't match the actual scripts that are given to me in my control panel for Pendo. Also, their YouTube walk-throughs are 4 years old and look like they were written for Angular JS.

I followed the documentation located at https://support.pendo.io/hc/en-us/articles/360031862272-Installation-for-Single-Page-Frameworks

I placed the first part of my script on the index.html page just before the closing <body> tag.

I then placed the pendo.initialize in my authorization component.

However, that did not work. I get ERROR TypeError: "pendo.initialize(...) is not a function" in my browser console.

So I contacted support and they suggested that I run the pendo.initialize outside of Angular using an ngZone.

Does anyone have any idea what needs to be modified to initialize pendo without an undefined error?

So this is where I've ended up.

index.html

...
    <script>
        (function (apiKey) {
            (function (p, e, n, d, o) {
                var v, w, x, y, z; o = p[d] = p[d] || {}; o._q = [];
                v = ['initialize', 'identify', 'updateOptions', 'pageLoad']; for (w = 0, x = v.length; w < x; ++w)(function (m) {
                    o[m] = o[m] || function () { o._q[m === v[0] ? 'unshift' : 'push']([m].concat([].slice.call(arguments, 0))); };
                })(v[w]);
                y = e.createElement(n); y.async = !0; y.src = 'https://cdn.pendo.io/agent/static/' + apiKey + '/pendo.js';
                z = e.getElementsByTagName(n)[0]; z.parentNode.insertBefore(y, z);
            })(window, document, 'script', 'pendo');
        })('xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx');
    </script>

</body>

In my login component

declare let pendo: any;
...
constructor(        
        private ngZone: NgZone
    ) {
...
}
...
private onAuthorizationResultComplete(authorizationResult: AuthorizationResult) {

        if (authorizationResult.authorizationState === AuthorizationState.unauthorized) {
            ...
        } else {
            this.httpClient.post(this.apiUrl, {}).subscribe(r => {
                this.ngZone.runOutsideAngular(function () {
                    pendo.initialize({
                        visitor: {
                            id: 'VISITOR-UNIQUE-ID-test'
                        },
                        account: {
                            id: 'ACCOUNT-UNIQUE-ID-test'
                        }
                    })('xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx');
                });

                this.router.navigate(['/dashboard']);
            });

        }
    }
    ```

Solution

  • Here is a working version of all that it required for installing Pendo via the Index.html page, and then initializing the pendo object in the component that verifies a user is signed.

    The key here is to not include the key with the pendo.initialize method.

    Index.html

    <!doctype html>
    <html lang="en">
    
    <head>
        <meta charset="utf-8">
        <title>AngularPendo</title>
        <base href="/">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="icon" type="image/x-icon" href="favicon.ico">
        <script>
            (function(apiKey) {
                (function(p, e, n, d, o) {
                    var v, w, x, y, z;
                    o = p[d] = p[d] || {};
                    o._q = [];
                    v = ['initialize', 'identify', 'updateOptions', 'pageLoad'];
                    for (w = 0, x = v.length; w < x; ++w)(function(m) {
                        o[m] = o[m] || function() {
                            o._q[m === v[0] ? 'unshift' : 'push']([m].concat([].slice.call(arguments, 0)));
                        };
                    })(v[w]);
                    y = e.createElement(n);
                    y.async = !0;
                    y.src = 'https://cdn.pendo.io/agent/static/' + apiKey + '/pendo.js';
                    z = e.getElementsByTagName(n)[0];
                    z.parentNode.insertBefore(y, z);
                })(window, document, 'script', 'pendo');
            })('xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'); // The Pendo API must stay here with the rest of the Pendo snippet
        </script>
    </head>
    
    <body>
        <app-root></app-root>
    </body>
    
    </html>
    

    Authorization component

    import { Component, OnInit, NgZone } from '@angular/core';
    import { Router } from '@angular/router';
    import { HttpClient } from '@angular/common/http';
    
    declare let pendo: any;
    
    @Component({
      selector: 'app-signin',
      templateUrl: './signin.component.html',
      styleUrls: ['./signin.component.scss']
    })
    export class SigninComponent implements OnInit {
    
      isAuthorized = true;
      // just need any API URL so we can get a response...doesn't need to be anything specific
      private apiUrl = 'https://api.github.com/users/godfathr';
    
      constructor(private router: Router, private ngZone: NgZone, private httpClient: HttpClient) { }
    
      ngOnInit() {
        this.onAuthorizationResultComplete(this.isAuthorized);
      }
    
      private onAuthorizationResultComplete(authorizationResult: boolean) {
    
        if (!authorizationResult) {
            console.log('I am not authorized');
        } else {
          console.log('I am authorized');
          // After verifying that a user is authorized, we put the pendo.initialize inside whatever
          // method we need for our app. In this case, it's a redirect to a landing page.
          // They important thing here is to remember not to include the API key with the initialize method.
          this.httpClient.get(this.apiUrl, {}).subscribe(r => {
                pendo.initialize({
                    visitor: {
                        id: 'VISITOR-UNIQUE-ID-test'
                    },
                    account: {
                        id: 'ACCOUNT-UNIQUE-ID-test'
                    }
                });
    
                this.router.navigate(['/authorized']);
            });
        }
      }
    }