Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why routerLink and router.navigate() act differently?

When using this code in HTML:

 <button [routerLink]="[{ outlets: { flow: ['step1'] } }]">click me to show step1</button>

it navigates correctly to '/child/(flow:step1)'!!!

When trying to use this code in Typescript:

this.router.navigate([{ outlets: { flow: ['step1'] } }]);

it trying to navigate to wrong path '/child(flow:step1)'!!!

It just missing the slash.

Service:

import { Injectable } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { EventBusService } from '../../../services/eventBus/eventBus.service';
import { RouterService } from '../../../services/router.service';

@Injectable()
export class FlowManagerService {
  constructor(private router: Router, private r: ActivatedRoute, private     eventBus: EventBusService, private routerService: RouterService) {
  }

  initValidStep() {
    return     (parseInt(this.routerService.currentUrlName.substr(this.routerService.currentUrlName.indexOf('step'), 5).replace('step', ''), 10) === 1);
  }

  goToFirstStep() {
    this.router.navigate([{ outlets: { flow: ['step1'] } }], {relativeTo: this.r});

    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_NEXT);
    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_BACK);
  }

  next(params) {
    const currentStep = this.routerService.currentUrlName.substr(this.routerService.currentUrlName.indexOf('step'), 5).replace('step', '');

    this.eventBus.emit(this.eventBus.globalEvents.FLOW.FLOW_STEP_CHANGE, ({
      type: 'NEXT'
    }));
    this.router.navigate([{ outlets: { flow: [`step${parseInt(currentStep, 10) + 1}`, params] } }], {relativeTo: this.r});

    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_NEXT);
    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_BACK);

  }

  back(params) {
    const currentStep = this.routerService.currentUrlName.substr(this.routerService.currentUrlName.indexOf('step'), 5).replace('step', '');

    this.eventBus.emit(this.eventBus.globalEvents.FLOW.FLOW_STEP_CHANGE, ({
      type: 'NEXT'
    }));
    this.router.navigate([{ outlets: { flow: [`step${parseInt(currentStep, 10) - 1}`, params] } }], {relativeTo: this.r});

    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_NEXT);
    this.eventBus.off(this.eventBus.globalEvents.FLOW.FLOW_STEP_BACK);
  }

}

Here is the Module using the Service above:

import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { FlowManagerService } from './service/flowManager.service';
import { CommonModule } from '@angular/common';

@NgModule({
  providers: [FlowManagerService],
  imports: [
    RouterModule,
    CommonModule
  ]
})
export class FlowManagerModule {

}
like image 989
Vladi Isakov Avatar asked Aug 11 '17 09:08

Vladi Isakov


People also ask

What is the difference between routerLink and router navigate?

router. navigate should navigate to exactly the same url if the same arguments are specified. routerLink works on any element, not only on <a> and <button> . Another main difference is, that for relative navigation, you need to pass the route to the relativeTo parameter with this.

What is difference between this router navigate and this router navigateByUrl?

It has two methods, navigate and navigateByUrl , that navigate the routes. They are similar; the only difference is that the navigate method takes an array that joins together and works as the URL, and the navigateByUrl method takes an absolute path.

What is difference between routing and navigation?

Providing clear and understandable navigation elements decides the success of an application. Angular provides extensive set of navigation feature to accommodate simple scenario to complex scenario. The process of defining navigation element and the corresponding view is called Routing.

What is difference between routerLink and href?

Href is the basic attribute provided by Html to navigate through pages which reloads the page on click. routerLink is the attribute provided by angular to navigate to different components without reloading the page.


1 Answers

Because routerLink uses relativeTo option implicitly:

export class RouterLink {
  ...
  get urlTree(): UrlTree {
    return this.router.createUrlTree(this.commands, {
      relativeTo: this.route, <----

You need to provide it explicitly in router.navigate:

constructor(private route: ActivatedRoute)

this.router.navigate([{ outlets: { flow: ['step1'] } }], {relativeTo: this.route});

Here is plunker and the complete working code:

import { Component, NgModule } from '@angular/core'
import { BrowserModule } from '@angular/platform-browser'
import { RouterModule, Routes, Resolve, Router, ActivatedRoute } from '@angular/router';
import { APP_BASE_HREF } from '@angular/common';

@Component({
  selector: 'my-app',
  template: `
      <div id='my-app'>
          <router-outlet></router-outlet>
      </div>
  `,
})
export class App {
  constructor() {
  }
}

@Component({
  selector: 'master-page',
  template: `
      <div id='master-page'>
          <div>Master Component</div>
          <button (click)='clickFirst()'>Inner Section 1</button>
          <button (click)='clickSecond()'>Inner Section 2</button>
          <router-outlet name='child'></router-outlet>
      </div>
  `
})
export class Master {
  constructor(private router: Router, private activeRouter: ActivatedRoute) {
  }

  clickFirst() {
    this.router.navigate([{outlets: {child: 'details1'}}], {relativeTo: this.activeRouter});
  }


  clickSecond() {
    this.router.navigate([{outlets: {child: 'details2'}}], {relativeTo: this.activeRouter});
  }
}

@Component({
  template: `
      <div>
          This content is in the "Inner" page (1)
      </div>
  `
})
export class Details1 {
  constructor() {
  }
}

@Component({
  template: `
      <div>
          This content is in the "Inner" page (2)
      </div>
  `
})
export class Details2 {
  constructor() {
  }
}

const routes: Routes = [
  {
    path: 'master',
    component: Master,
    children: [
      {
        path: 'details1',
        component: Details1,
        outlet: 'child'
      },
      {
        path: 'details2',
        component: Details2,
        outlet: 'child'
      }
    ]
  },
  {
    path: '',
    pathMatch: 'prefix',
    redirectTo: 'master'
  }
];

@NgModule({
  imports: [BrowserModule, RouterModule.forRoot(routes)],
  declarations: [App, Master, Details1, Details2],
  providers: [{
    provide: APP_BASE_HREF,
    useValue: '/'
  }],
  bootstrap: [App]
})
export class AppModule {
}
like image 121
Max Koretskyi Avatar answered Nov 16 '22 02:11

Max Koretskyi