The issue with Angular 2's router.navigate not functioning as expected within a nested JavaScript function

Consider the app module:

import { NgModule }       from '@angular/core';
import { BrowserModule }  from '@angular/platform-browser';
import { FormsModule }    from '@angular/forms';
import { RouterModule }   from '@angular/router';
import {NgbModule} from '@ng-bootstrap/ng-bootstrap';

import { AppComponent }        from './app.component';
import {DashboardComponent} from "./components/dashboard/dashboard.component";
import {LogoutComponent} from "./components/logout/logout.component";
import {LoginComponent} from "./components/login/login.component";
import {HttpModule} from "@angular/http";
import {PrescribeComponent} from "./components/prescribe/prescribe.component";

@NgModule({
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    NgbModule.forRoot(),
    RouterModule.forRoot([
      {
        path: 'dashboard',
        component: DashboardComponent
      },
      {
        path: 'logout',
        component: LogoutComponent
      },
      {
        path: 'login',
        component: LoginComponent
      },
      {
        path: 'prescribe',
        component: PrescribeComponent
      }

    ])
  ],
  declarations: [
    AppComponent,
    DashboardComponent,
    LogoutComponent,
    LoginComponent,
    PrescribeComponent
  ],
  providers: [
    //HeroService
  ],
  bootstrap: [ AppComponent ]
})
export class AppModule {
}

Now, let's focus on a specific component:

import {Component} from '@angular/core';
import {Router} from "@angular/router";
declare var ExternalJS: any;

@Component({
  selector: 'my-app',
  templateUrl: 'app/components/login/login.component.tpl.html',
})
export class LoginComponent {

  public redirect;
  public username: string;
  public password: string;

  constructor(public _router: Router) {

    this.username = 'someUsername';
    this.password = 'SomePassword';


  }
  doLogin() {

    var self = this;

    ExternalJS.authenticateByUser({username: this.username, password: this.password}, (response => {


     self._router.navigate(['/dashboard']);


    }));
  }

}

The issue arises when navigating to the dashboard as the route disappears in the URL.

As a result, instead of seeing http://localhost:3001/dashboard, only http://localhost:3001/ is displayed.

Moving the navigation outside of the JavaScript function solves the problem. But, it needs to be inside the callback function.

In an updated version of the code provided:

doLogin() {

    var self = this;
    self.goToRoute(); //MOVED TO HERE. WORKING FINE.

    /*ExternalJS.authenticateByUser({username: this.username, password: this.password}, ((response:any) => {   

           self.goToRoute();
         })


    }));*/
  }

Following insights from Gunter's comments, here is a refined version that works efficiently:

doLogin() {

    ExternalJs.authenticateByUser({username: this.username, password: this.password}, (response => {
      var self = this;
      ExternalJs.setUser(12398787, "user1", function () {
        ExternalJs.subscribeEvent({
          eventName: 'user.select',
          callback: (data => {
            self.zone.run(() => {
              self._router.navigate(['./dashboard']);
            });
          })
        });
      });
    }));
  }

Further enhancements were made in Update 4 to ensure the hash remains intact after implementing zone in the app module:

providers: [
    {provide: LocationStrategy, useClass: HashLocationStrategy}
  ]

This resolves the disappearing hash issue.

Answer №1

To ensure proper execution of the code within Angular's zone, it is important to make sure that change detection runs smoothly. Otherwise, the router.navigate() function may not work as intended:

constructor(public _router: Router, private zone:NgZone) {
ExternalJS.authenticateByUser({username: this.username, password: this.password}, (response => {
  this.zone.run(() =>  
    this._router.navigate(['/dashboard']);
  });
}));

When using =>, there is no need for self

Answer №2

After some troubleshooting, I managed to find a solution by implementing the following code snippet:

 navigateToDashboard(){

    this._router.navigate(['/dashboard']);

  }

Subsequently, the authentication process was handled by invoking an external JavaScript function with the user's credentials:

ExternalJS.authenticateByUser({username: this.username, password: this.password}, (response => {
  self.navigateToDashboard()
}));

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 are effective strategies for troubleshooting Dependency Injection problems in nest.js?

Can someone explain the process of importing a third-party library into NestJS using Dependency Injection? Let's say we have a class called AuthService: export class AuthService { constructor( @Inject(constants.JWT) private jsonWebToken: any, ...

Determine the generic parameter of the output type by analyzing the resolved value of a data type within the function

I am looking to automatically determine the generic parameter of the return type by utilizing the resolved value of a type within the function. Consider the following: export type Context = any; export type Handler<T> = (ctx: Context) => Promise& ...

Unlock the power of Angular Component methods even when outside the Angular library with the help of @ViewChild()

In my Angular library, there is a component called AComponent which has its own template, methods, and properties. Once the Angular library is packaged, it becomes available as a NuGet package for other projects to utilize. @Component({ selector: ' ...

Angular 6 provides a regular expression that specifically targets the removal of any characters that are not numbers and enforces the allowance of

I have tried various solutions to restrict input in an Angular material input box, but none seem to be effective for my specific case. I need the input field to only allow numbers and a decimal point. Any other characters should be automatically removed as ...

Tips for effectively combining the map and find functions in Typescript

I am attempting to generate an array of strings with a length greater than zero. let sampleArray2:string[] = ["hello","world","angular","typescript"]; let subArray:string[] = sampleArray2 .map(() => sampleArray2 .find(val => val.length & ...

The combination of using the .share() method with the .subscribe() method is resulting in

I encountered an issue while attempting to utilize share() with subscribe(). Despite starting with subscribe, I received the following error message. How can this be resolved? The main goal is to execute the logic within subscribe. Share is necessary to p ...

Navigating between different views and pages within Angular FullCalendar can be achieved by utilizing the appropriate handlers for next,

After successfully integrating Angular fullCalendar into my Angular project and displaying events that I can click on, I found myself stuck when trying to handle clicks on the next and prev buttons as well as view changes. Unfortunately, the official docum ...

The Value Entered in Angular is Unsaved

I have encountered an issue with my app's table functionality. The user can enter information into an input field and save it, but upon refreshing the page, the field appears empty as if no data was entered. Can someone please review my code snippet b ...

Transferring information to a deep-level interface

I am currently working on creating an object that aligns with my interface structure. Success Story export interface ServiceDataToDialog { id: number, service: string, } constructor(private _dialogRef: MatDialogRef<DialogServiceTabletAddRowComp ...

Utilizing Angular's Mat-Table feature to dynamically generate columns and populate data in a horizontal manner

I am in need of a solution where I must populate the mat-table in a horizontal format with an array of JSON objects. The input array is as follows: [{ "SAMPLERULEID": 69, "SAMPLERULENAME": "Sample1", &q ...

Enhance Vue TypeScript components with custom component-level properties

In my vue2 project, I am utilizing vue-class-component along with vue-property-decorator. My goal is to implement component-level security validation for each component when it loads. I imagine implementing it with a signature like this: @Component @Secur ...

Interactive Bootstrap 4 button embedded within a sleek card component, complete with a dynamic click event

I am trying to create a basic card using bootstrap 4 with the following HTML code. My goal is to change the style of the card when it is clicked, but not when the buttons inside the card are clicked. Currently, clicking on the test1 button triggers both ...

A promise was caught with the following error: "Error in ./Search class Search - inline template:4:0 caused by: Maximum call stack size exceeded"

As a newcomer to Angular2, I am currently developing a web application that requires three separate calls to a REST API. To test these calls, I decided to simulate the API responses by creating three JSON files with the necessary data. However, my implemen ...

Issue encountered while using Typescript with mocha: Unable to utilize import statement outside a module

Exploring the world of unit testing with mocha and trying to create a basic test. Project Structure node_modules package.json package-lock.json testA.ts testA.spec.ts tsconfig.json tsconfig.json { "compilerOptions": { "target&qu ...

In TypeScript, the catch block does not get triggered

I created a custom pipe in Angular that is supposed to format passed parameters to date format. The pipe contains a try-catch block to handle any errors, but surprisingly the catch block never seems to be executed even when an invalid date is passed. impo ...

Tips for resolving the "trim" of undefined property error in Node.js

Looking to set up a basic WebAPI using Firebase cloud functions with express and TypeScript. Here's the code I have so far: import * as functions from 'firebase-functions'; import * as express from 'express'; const app = express( ...

Using jQuery in Jest test with Angular 5: A step-by-step guide

I am facing an issue with my Angular component that utilizes a CalendarService. Upon initialization of the component, I invoke the "calendarService.init()" method. The CalendarService is responsible for configuring a semantic-ui-calendar (which relies on ...

Issues with enabling drag and drop disable flags for columns in Angular Material Table

Currently, I have implemented an angular material table with the following configuration: <table mat-table [ngStyle]="{'height': '600px'}" [dataSource]="items" multiTemplateDataRows matSort ...

Eliminate spacing in MaterialUi grids

As I work on a React project, I am faced with the task of displaying multiple cards with content on them. To achieve this layout, I have opted to use MaterialUi cards within Material UI grids. However, there seems to be an issue with excessive padding in t ...

When you add the /deep/ selector in an Angular 4 component's CSS, it applies the same style to other components. Looking for a fix?

Note: I am using css with Angular 4, not scss. To clarify further, In my number.component.css file, I have: /deep/ .mat-drawer-content{ height:100vh; } Other component.css files do not have the .mat-drawer-content class, but it is common to all views ...