RevealBi / Reveal.Sdk

Issue tracker - Reveal SDK https://www.revealbi.io/
https://www.revealbi.io/
3 stars 0 forks source link

[BUG]: Issue when using Google charts and Reveal. #66

Closed federicoprovera closed 12 months ago

federicoprovera commented 1 year ago

Company

Infragistics

SDK Version

1.3.1

Client Framework

Angular

Server Platform

ASP.NET

Description

Customer reports:

"We just discovered a problem - the Reveal js script is breaking some of our non-Reveal code, specifically these donut charts. The first video illustrates current behavior, and the second video illustrates how it used to work before adding Reveal (I commented out the infragistics.reveal.js script in index.html and $.ig.RevealSdkSettings.setBaseUrl/setAdditionalHeadersProvider code). Front end arch is Angular Typescript and the donut charts are dependent on angular-google-charts 2.2.3 npm package. Anyone have any ideas or workarounds to fix this?"

We were able to reproduce the issue. When creating a couple pie charts using Google Chart and hovering over the slices in the bottom, it fails with the following error:

zone.js:182 Uncaught RangeError: Maximum call stack size exceeded at gvjs_0e (jsapi_compiled_default_module.js:70:17) at gvjs_0e (jsapi_compiled_default_module.js:70:413) at gvjs_0e (jsapi_compiled_default_module.js:70:413) at gvjs_0e (jsapi_compiled_default_module.js:70:413) at gvjs_0e (jsapi_compiled_default_module.js:70:413) at gvjs_0e (jsapi_compiled_default_module.js:70:413) at gvjs_0e (jsapi_compiled_default_module.js:70:413) at gvjs_0e (jsapi_compiled_default_module.js:70:413) at gvjs_0e (jsapi_compiled_default_module.js:70:413) at gvjs_0e (jsapi_compiled_default_module.js:70:413)

Steps for reproduce:

1) Create an angular client app, as described here: https://help.revealbi.io/web/getting-started-angular/

2) Install google charts with npm, as described here: https://www.npmjs.com/package/angular-google-charts/v/2.2.3

3) Use this index.html:

4) Use this app/app.component.html

<div #revealView style="height: 100vh; width: 100%; position:relative;">

5) Use this app/app.module.ts

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component'; import { GoogleChartsModule} from 'angular-google-charts'

@NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, GoogleChartsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }

6) Run the application with ng server --open

7) Opening the browser inspect, hover on the google charts until they fail with the error described above.

brianlagunas commented 1 year ago

Tracked with internal issue AB#26260

TorreyBetts commented 12 months ago

Hi!

We have found the cause of the issue and unfortunately it's out of our hands, although I have created a workaround. Reveal extends some of the native prototypes in JS to add additional features and enhance functionality. Google Charts didn't appear to account for developers extending the JS prototypes and the result is a cyclic reference within their code when they clone objects and iterate through properties.

To workaround this issue, you'll need to pin a version so function name changes don't affect your code. In this workaround code I used version 51.

google.charts.load('51', { 'packages': ['corechart'] });

The monkey patch workaround is as follows. I'll include TypeScript as well as JavaScript so that you can take advantage of either place you may want to use it in your Angular app.

TypeScript

    window.gvjs_0e = function(a: any): any {    
        if (typeof a !== 'object' || a === null) {
            return a;
        }

        if (typeof a.clone === 'function') return a.clone();
        if (typeof Map !== 'undefined' && a instanceof Map) return new Map(a);
        if (typeof Set !== 'undefined' && a instanceof Set) return new Set(a);

        const isArray = Array.isArray(a);
        let b: any = isArray ? [] : {};

        for (let c in a) {
            if (a.hasOwnProperty(c)) {
                b[c] = window.gvjs_0e(a[c]);
            }
        }

        return b;
    }; 

JavaScript

window.gvjs_0e = function(a) {    
    if (typeof a !== 'object' || a === null) {
        return a;
    }

    if (typeof a.clone === 'function') return a.clone();
    if (typeof Map !== 'undefined' && a instanceof Map) return new Map(a);
    if (typeof Set !== 'undefined' && a instanceof Set) return new Set(a);

    const isArray = Array.isArray(a);
    let b = isArray ? [] : {};

    for (let c in a) {
        if (a.hasOwnProperty(c)) {
            b[c] = window.gvjs_0e(a[c]);
        }
    }

    return b;
};

The magic of the fix is the hasOwnProperty usage as it helps skip over properties that were added to the prototype.

With this reply I'll close this issue. Feel free to reply if you have further questions.

gary-calpo-lts commented 12 months ago

@TorreyBetts Good morning. We used your workaround to resolve the Google Charts issue in our app. Thank you!