Angular's mechanism for detecting changes in a callback function for updates

I have come across a puzzling scenario regarding a basic issue. The situation involves a simple component with a boolean property that is displayed in the template of the component. When I update this property within a callback function, the property is updated internally within the component, but the modified value is not reflected in the rendering. As a result, the change detection does not occur automatically, and I find myself having to trigger it manually by calling

changeDetectorRef.detectChanges();
in order to display the updated value.

This is how the template looks:

<div *ngIf="isUserLoggedIn">
      <router-outlet></router-outlet>
</div>
<div *ngIf="!isUserLoggedIn">
    <div id="googleBtn" (click)="onSignIn()">Sign In</div>
</div>

And here's the relevant code from the component:

gapi.load('auth2', () => {
      this.auth2 = gapi.auth2.init({
        client_id: '769107420471-782b0i2f3dt9u05dhrb4j21g7ajglrg6.apps.googleusercontent.com',
        cookiepolicy: 'single_host_origin',
        scope: 'profile email'
      });
      var googleBtn = document.getElementById('googleBtn');
      if(googleBtn) {
        this.attachSignin(document.getElementById('googleBtn'));
      }
    });
  }
  public attachSignin(element) {
    this.auth2.attachClickHandler(element, {},
      (googleUser) => {
        this.signUpService.googleLogin(googleUser.getAuthResponse().id_token, 
        this.successCallback.bind(this), 
        this.signOut.bind(this));
      }, (error) => {
        alert(JSON.stringify(error, undefined, 2));
      });
  }

  successCallback = function (data) {
    // this.changeDetectorRef.detectChanges();
    this.isUserLoggedIn = this.utils.isUserLoggedIn();
  }

The expected behavior is as follows: initially, "isUserLoggedIn" is set to false. When the user clicks on the "Sign In" button, a function from another service is called which toggles the value of "isUserLoggedIn" in the successCallback of that function. This should also lead to the corresponding toggling of elements in the template.

However, I find it perplexing that I need to manually invoke

changeDetectorRef.detectChanges()
in order to see the changes in the DOM. I wonder why the change detection mechanism fails to work seamlessly in this callback scenario. Interestingly, when I tested it differently using a simple example like
Observable.interval(2000).subscribe(x => {this.isUserLoggedIn = !this.isUserLoggedIn});
, the change detection worked perfectly fine without any manual intervention.

Answer №1

The issue arises due to the load event callback being triggered outside of the Angular zone. To resolve this, you can implement the following solution:

constructor(private zone: NgZone) {}

gapi.load('auth2', () => {
    zone.run(() => {
        this.auth2 = gapi.auth2.init({
            client_id: '769107420471-glrg6.apps.googleusercontent.com',
            cookiepolicy: 'single_host_origin',
            scope: 'profile email'
        });
        var googleBtn = document.getElementById('googleBtn');

To learn more about this topic, refer to:

  • Exploring the necessity of NgZone (zone.js) for change detection in Angular

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

What methods can be used to accurately display the data type with TypeOf()?

When working with the following code: const data = Observable.from([{name: 'Alice', age: 25}, {name: 'Bob', age: 35}]); console.log(typeof(data)); The type is displayed as Object(). Is there a way to obtain more specific information? ...

Obtaining only the updated objects from a web API in C#

When fetching data from a c# web api to my angular app, I notice that all the data is being polled every time, even if most of it remains unchanged. What I really want is to only retrieve and update the objects that have been modified in some way. Here&ap ...

Deciding between bundling a Typescript package and using tsc: When is each approach the best choice

When it comes to publishing a Typescript NPM package (library, not client), I have two main options: 1. Leveraging Typescript's compiler First option is to use the Typescript compiler: tsc and configure a tsconfig.json file with an outDir setting: { ...

How to reference an array from one component to another in Angular 2

Within my AddUserComponent, I have a public array declared like this: public arr: Array<any> = [] This array stores the names of users. Now, I need to access these values in another component called AddTopicComponent in order to display the user&a ...

What is the best way to verify that all elements within an object are 'false' except for one that is 'true'?

I am working with an object that has multiple boolean fields: type SomeObject = { A: boolean B: boolean C: boolean .... } Is there a simple and efficient method to determine if all other fields (except for a specified one) are set to false? We co ...

Stop focusing on mat-select after a selection is made

I am encountering an issue with the following code in my .html file: <mat-form-field> <mat-select #selector(selectionChange)="onSelectionChange($event.value)"> <mat-option *ngFor="let test of tests" [value]="test"> </ma ...

Leveraging Shared and CoreModule in Ionic

In the recommended styleguide found at https://angular.io/guide/styleguide#core-feature-module, it is suggested to implement a SharedModule and CoreModule in an Angular application. I am curious if utilizing these modules would also be beneficial in an Io ...

Guide to incorporating Jquery-Comment into Angular versions 2 and beyond

I've incorporated the Jquery-Comment plugin into my Angular 2 project by adding the necessary script and css files to my Index.html page. However, when initializing the Comment TextBox id within a script tag, I encountered an error in the console. ...

Receiving user input in Angular 6 for a function

Need help getting input from a text box and passing it to a function. Encountering the error message "_co.randomCode is not a function." New to Angular and have tried various approaches but can't seem to solve this issue. app.component.html <div ...

The TypeScript error occurs when attempting to assign a type of 'Promise<void | Object>' to a type of 'Promise<Object>' within a Promise.then() function

I'm currently working on a service to cache documents in base64 format. The idea is to first check sessionStorage for the document, and if it's not there, fetch it from IRequestService and then store it in sessionStorage. However, I've encou ...

Is it possible to dynamically retrieve an element's style from @ViewChild in an Angular 2 component without needing an active approach?

For instance, there's an element in the template that uses a local variable #targetElement to retrieve its current width whenever needed. However, I prefer not to calculate the style programmatically. I attempted using a setter with the @ViewChild ann ...

Issue when transferring properties of a component to a component constructed Using LoadingButton MUI

Check out my new component created with the LoadingButton MUI: view image description here I'm having issues passing props to my component: view image description here Dealing with a TypeScript problem here: view image description here I can resolv ...

What is the best way to map elements when passing props as well?

In my code, I am using multiple text fields and I want to simplify the process by mapping them instead of duplicating the code. The challenge I'm facing is that these textfields also require elements from the constructor props. import React, { Compon ...

A step-by-step guide on incorporating MarkerClusterer into a google-map-react component

I am looking to integrate MarkerClusterer into my Google Map using a library or component. Here is a snippet of my current code. Can anyone provide guidance on how I can achieve this with the google-map-react library? Thank you. const handleApiLoaded = ({ ...

Sharing data between sibling components becomes necessary when they are required to utilize the *ngIf directive simultaneously

Within my parent component, I am hosting 2 sibling components in the following manner: <div *ngif="somecode()"> <sibling1> </sibling1> </div> <div *ngif="somecode()"> <sibling1 [dataParams]=sibling1object.somedata> ...

Exploring Angular 10: Managing Two Promises in ngOnInit

I am currently working on integrating the Strava API into my Angular app. To summarize briefly: When a user clicks on a button to connect to Strava They are redirected to Strava for authentication (using PKCE) Strava then redirects back to my app with a ...

Having trouble applying [formControl] to a set of radio buttons in Angular2

Currently, I am encountering an issue with a list of groups of radio buttons in Angular2. My objective is to bind the value of each group of radio buttons using [formControl]. However, when implementing this, the radio buttons seem to lose their normal mut ...

Strange behavior of the .hasOwnProperty method

When attempting to instantiate Typescript objects from JSON data received over HTTP, I began considering using the for..in loop along with .hasOwnProperty(): class User { private name: string; private age: number; constructor(data: JSON) { ...

Determine through programming whether an ng-content slot has been filled in Angular

I have developed a dynamic Angular component that utilizes content projection and slots in the following way: <div class="content-wrapper"> <div class="short-wrapper" [style.opacity]="expanded ? 0 : 1"> ...

What is the process for utilizing the TypeScript compiler with nodejs?

I have a sample code saved in a file called hello.ts Upon the completion of nodejs setup on Windows, execute the following command to install typescript: npm install -g typescript Is there a way to compile hello.ts directly with node.js? While using "T ...