Angular DOM not reflecting updates

Having trouble with the view not detecting changes in value on a component. I've attempted to use ChangeDetectorRef without success. After trying various solutions and spending an excessive amount of time on something that should work smoothly, it seems like there might be an issue with how the gapi is handling the onsuccess function. I've tried binding it down and wrapping it in different functions, but nothing seems to resolve the problem.

The onsuccess function executes almost immediately, but even after logging out and back in, the same results persist.

Do you think there's something crucial that I'm overlooking here?

header.component.html
<mat-toolbar color="">
    <span routerLink="">Hub</span>
  <span class="spacer"></span>
  <ul >
    <li [hidden]="!userIsAuthenticated" >
      <a mat-button (click)="onLogout()" routerLinkActive="mat-accent">LogOut</a>
    </li>
    <li [hidden]="userIsAuthenticated">
      <app-google-signin></app-google-signin>
    </li>
  </ul>
</mat-toolbar>

header.component.ts
import {AfterViewInit, ChangeDetectorRef, Component, OnDestroy, OnInit} from '@angular/core';
import {AuthService} from '../auth/auth.service';
import {Subscription} from 'rxjs';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit, OnDestroy {
  private userIsAuthenticated = false;
  private loggingIn = false;
  private authStatusListenerSub: Subscription;
  private loggingInSub: Subscription;

  constructor(private authService: AuthService, private ref: ChangeDetectorRef) {
  }

  ngOnInit() {
    this.userIsAuthenticated = this.authService.getIsAuthenticated();
    this.loggingInSub = this.authService.getLoggingInListener().subscribe(loggingIn => {
      this.loggingIn = loggingIn
      console.log(`Logging In: ${loggingIn}`)
      this.ref.markForCheck()
    })

    this.authStatusListenerSub = this.authService.getAuthStatusListener().subscribe(isAuthenticated=>{
      this.userIsAuthenticated = isAuthenticated
      console.log(`Authenticated: ${isAuthenticated}`)
    });

  }


  ngOnDestroy() {
    this.authStatusListenerSub.unsubscribe();
  }
}


auth.service.ts
import {EventEmitter, Injectable, Output} from '@angular/core';
import {HttpClient} from '@angular/common/http';
import {Subject} from 'rxjs';

declare const gapi: any;


@Injectable({
  providedIn: 'root'
})
export class AuthService {
  public CLIENT_ID = '[clientId]';
  private isAuthenticated = false;
  private loggingIn = false;

  @Output() authStatus = new EventEmitter<boolean>()

  private authStatusListener = new Subject<boolean>();
  private loggingInListener = new Subject<boolean>();

  constructor(private http: HttpClient) {
  }

  onGoogleSignIn(googleUser) {
    this.loggingIn = true;
    this.loggingInListener.next(true)
    const googleToken = googleUser.getAuthResponse().id_token;
    this.http.post<{ message: string, access: boolean }>(
      '[login url]',
      {loginToken: googleToken},
      {withCredentials: true})
      .subscribe(
        res => {
          console.log(res.message);
          this.loggingIn = false;
          this.loggingInListener.next(false)
          this.isAuthenticated = true;
          this.authStatusListener.next(true);
        },
        (err) => {
          this.loggingIn = false;
          this.loggingInListener.next(false)
          this.logout();
        });
  }


  getIsAuthenticated() {
    return this.isAuthenticated;
  }

  getAuthStatusListener() {
    return this.authStatusListener.asObservable();
  }

  getLoggingInListener() {
    return this.loggingInListener.asObservable()
  }
}
google-signin.component.ts
import {AfterViewInit, Component, ElementRef, OnInit} from '@angular/core';
import {AuthService} from '../auth.service';

declare const gapi: any;


@Component({
  selector: 'app-google-signin',
  templateUrl: './google-signin.component.html',
  styleUrls: ['./google-signin.component.scss']
})
export class GoogleSigninComponent implements OnInit, AfterViewInit {
  public auth2: any;

  constructor(
    private element: ElementRef,
    private authService: AuthService,
  ) {
  }

  ngOnInit() {

  }

  ngAfterViewInit() {
    this.googleInit();
  }


  public googleInit() {
    gapi.load('auth2', () => {
      this.auth2 = gapi.auth2.init({
        client_id: this.authService.CLIENT_ID,
        cookie_policy: 'single_host_origin',
      });

      const element = gapi.signin2.render('app-google-signin', {
        scope: 'profile email',
        longtitle: true,
        theme: 'dark',
        onsuccess: this.authService.onGoogleSignIn.bind(this.authService),
        onfailure: err => console.log(err)
      });
    });
  }

}

Answer №1

Make sure to manually trigger change detection and utilize the onPush change detection strategy.

 @Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush // include this 
})
export class HeaderComponent implements OnInit, OnDestroy {
  private userIsAuthenticated = false;
  private loggingIn = false;
  private authStatusListenerSub: Subscription;
  private loggingInSub: Subscription;

  constructor(private authService: AuthService, private cdr: ChangeDetectorRef) {
  }

  ngOnInit() {
    this.userIsAuthenticated = this.authService.getIsAuthenticated();
    this.loggingInSub = this.authService.getLoggingInListener().subscribe(loggingIn => {
      this.loggingIn = loggingIn
      console.log(`Logging In: ${loggingIn}`)
      this.cdr.detectChanges(); // *manually triggering change detection here*
    })

    this.authStatusListenerSub = this.authService.getAuthStatusListener().subscribe(isAuthenticated=>{
      this.userIsAuthenticated = isAuthenticated
      console.log(`Authenticated: ${isAuthenticated}`)
    });

  }


  ngOnDestroy() {
    this.authStatusListenerSub.unsubscribe();
  }
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The Angular ReactiveForm encounters issues with recognizing the parent formGroup directive when working with a recursive template

In my application, I generate formGroups dynamically based on a configuration object that follows this structure: const formElements: FormElementInterface[] = [ { type: 'formControl', defaultIsArray: false, defaultValue: 'Apple&ap ...

Encountered an issue with the core-js postinstall script, causing a failure

I encountered the following errors while attempting to install node modules in an existing Angular project. The installation is being carried out on a Windows machine (Win32 X64). > [email protected] postinstall node_modules\babel-runti ...

Tips for implementing <mat-progress-bar> in .ts file when making API service requests with Angular

I'm currently utilizing an API call to retrieve an image from a service, and I would like to display a progress bar while the image is being fetched. It seems that I need to incorporate the progress bar within the service as the image data is returned ...

Unlocking the Power of Angular's Default Input Required Validation

Just aiming to utilize the default required validation functionality in HTML. This is the code I've implemented: <form (ngSubmit)="submit()"> <div class="login-container"> <ion-item> <ion-input ...

The animation fails to retain its final state and reverts back to its initial state

Currently, I am diving into learning Angular 6 and encountered a small issue. Following this tutorial: Upon clicking the button, the animation executes as intended. However, after the fade-out effect, the text reappears abruptly. Any insights on why it re ...

Looking to compare the values of objects in one array with the values of objects in another array

Within this code snippet, I am attempting to retrieve the id of a variant that aligns with the selected objects const selected = [ { "id": 14 }, { "id": 95 } ] const variants = [ { "id": 1, "option_values": ...

The ngModal in Angular opens successfully, but users are unable to interact with any input fields or buttons

Issue: I am encountering a problem with a button inside a component that is supposed to open another component as a modal. The button successfully opens the modal, but I am unable to interact with any elements inside it, including inputs and the close butt ...

Angular 12 web version displays error message: "404 not found" for the requested URL

I recently completed my first website using Angular and uploaded it to the server successfully. When browsing through the pages, everything seems fine. However, I encountered an issue when trying to access specific URLs by copying and pasting them into the ...

Encountering an error when generating a universal header element for an Ionic application in the --prod build mode

Recently, I have been putting together an app using Ionic 3 that involves multiple pages with a consistent header. The challenge arises from the slight differences in elements inside this header across various pages. To avoid redundant code and adhere to t ...

Ways to loop through individual characters within a string

Is there a way to iterate through a string using the *ngFor? I have a string that contains binary code (e.g. 0010) and depending on each bit, I need to display a different icon. <div class="row" *ngFor="let item of subscribedCommandBus2Easy; let i = in ...

Upgrading from Angular version 12 to version 14: A Smooth Migration

After upgrading from Angular v12 to v13, I encountered issues while trying to delete the node_modules directory and reinstalling it using npm install. Unfortunately, I received the following errors: D:\test\Fxt\Web\src\main\ui ...

What is the earliest version of npm that I can install?

There was an error encountered while trying to install a package using npm. This issue is related to permission denied when attempting to fetch a specific URL. The error code EEXIST indicates that the file already exists in the specified ...

Troubleshooting date errors in react-datepicker using hookstate and Next.js

Exploring a page in the realm of nextjs: import type { NextPage } from "next"; import DatePicker from "react-datepicker"; import { useState as useStateHook } from "@hookstate/core"; import { useState as useStateReact } from &q ...

When I attempt to map imports in Typescript, an error occurs, stating, "Element implicitly has an 'any' type because the expression of type 'string' is being indexed into type 'typeof import'."

(parameter) key: string An issue arises where the expression of type 'string' cannot be used to index type 'typeof import("d:/Projects/Front/attendance-checker2/src/redux/modules/sagas")', leading to an implicit 'any&a ...

Is it possible to share a type exclusively among object properties based on the given value?

My goal is to create a custom React table component with the ability to select rows in single, multiple, or none selection modes. The current table component I am refactoring is quite large, so I want to simplify the setup and props as much as possible. I ...

Looking to change the pagination arrow icons in Angular's mat-paginator to something different. Let's replace them with new icons

Looking to customize the arrows icons on an Angular mat-paginator for a unique design. For more information on mat-paginator, please see this link: https://material.angular.io/components/paginator/overview I attempted to locate a way to change the icon by ...

`How can TypeScript be used to designate the type of a variable within the useState hook?`

I defined a variable called 'text' and a hook named 'setText'. I'm using them to update the value of a form input field. How can I ensure that 'text' is always of type string? This is what I attempted: interface TextInt ...

What is the best way to eliminate an animation from a component while using it within a different Angular Component?

I have developed an Angular Component that enhances the look of a photo with styling and animation effects. Now, I want to utilize the same styling for another component without applying the animation. Styling and Animation for the photo: .pic { position ...

Issue encountered with ng-include compatibility in Angular 5

Just getting started with Angular and working on a small test project using Angular 5 and Visual Code. I'm attempting to use ng-include but the template is not displaying. src add-device add-device.component.html add-device.com ...

What is the best way to implement an asynchronous function using a for loop and APIs in Typescript?

Struggling with ensuring my function returns data only after completing all API calls and the for loop. getListingsImages(sessionID, mlsSearchCriteria){ this.http.get(this.laconiaBaseURL + "mls/search/" + sessionID + "?" +querySt ...