2

I am trying to integrate the Google SSO using the Google Identity API's for the Angular 14 application.

The problem I am facing is, I can see the Sign In with Google button when I first come into Login screen. But if I go to other screen then do logout and when I am back to Login screen, the Sign In with google button is no more visible and I have to force refresh (Ctrl+Shift+R) to make it visible.

I have already gone through Why does the Sign In With Google button disappear after I render it the second time? but it is unclear how to make feasible in my case.

As I can see an Iframe will be rendered during the 1st time and if I come back again to login page from other page I can not see the Iframe and the SignIn button is not visible.

Here is the code to load the sign in button from angular component

ngOnInit() {
    // @ts-ignore
    window.onGoogleLibraryLoad = () => {
      // @ts-ignore
      window.google.accounts.id.disableAutoSelect();
    };

    this.loadGoogleSSOScript('2.apps.googleusercontent.com');
  }

  loadGoogleSSOScript(clientId: string) {
    // @ts-ignore
    window.onGoogleLibraryLoad = () => {
      // @ts-ignore
      google.accounts.id.initialize({
        client_id: clientId,
        itp_support: true,
        callback: this.handleCallback.bind(this),
      });
      // @ts-ignore
      google.accounts.id.renderButton(
        // @ts-ignore
        document.getElementById('g_id_onload'),
        { theme: 'filled_blue', size: 'medium', width: '200px' }
      );
      // @ts-ignore
      google.accounts.id.prompt(); // also display the  dialog
    };
  }

Here is the link for Stackblitz which has full code.

How to solve this issue?

Unknown
  • 2,037
  • 3
  • 30
  • 47

2 Answers2

0

In Angular you shouldn't directly access the DOM to get the element, you can use ViewChild.

//HTML
<div #gbutton></div> 
//TS
    export class LoginComponent implements OnInit, AfterViewInit {

    @ViewChild('gbutton') gbutton: ElementRef = new ElementRef({});
        
    constructor() { }
               
    ngAfterViewInit() {
       google.accounts.id.initialize({
            client_id: clientId,
            itp_support: true,
            callback: this.handleCallback.bind(this),
        });
    
        google.accounts.id.renderButton(
            this.gbutton.nativeElement,
            {
            type: "standard", theme: "outline",
            size: "medium", width: "50", shape: "pill", ux_mode: "popup",
            }
        )
    }
新Acesyyy
  • 1,152
  • 1
  • 3
  • 22
0

The way I solved this problem was to move the button to another place in the dom rather than allow it to be destroyed when my component is destroyed.

When I need the button again, I move it again. I use "display:none" when I'm storing the button in another location in the dom.

Here's an example of moving the button:

// to be called in onDestroy method of component that renders google button
storeButton() {
    const con = this.document.getElementById(this.storageConID);
    const btn = this.document.getElementById(this.googleButtonID);
    con!.insertBefore(btn as any, con?.firstChild || null);
  } 

However, I found that trying to move the button between locations too quickly, with multiple consecutive calls to el.insertBefore would actually cause the button to disappear from the dom altogether for some reason.

In my case, I was navigating between a login and a signup page and both needed to display the button. To get around that issue, I used a MutationObserver and made sure that I didn't try to move the button out of it's "storage" location until it was actually there.

I added this to my index.html as a place to store the button when it shouldn't be displayed.

<div id="google-btn-storage-con">
  <div id="google-btn" class="flex-row justify-center items-center hidden"></div>
</div>

The div with the id "google-btn" is the element I pass into the google.accounts.id.renderButton method to render the button initially on the page.

When I need to display the google button, then I move the div with the id "google-btn" into my component.

I hope that this little bit of code and explanation is enough. I would share more but the actual implementation of all this is hundreds of lines long (including using MutationObserver and dynamically loading the gsi script).

squirtgun
  • 629
  • 9
  • 12