Search code examples
typescriptnavigationangular10

How to navigate from one component to a particular division of another component in angular?


I want to navigate from one component using router.navigate(['/divofanothercomponent']) in angular. Given below is the code.

ts file of Component A

# imports
abc(){
alert('please login')
this.router.navigate(['/componentB'],{fragment:'drop1'});
}

html of component B

<section>  
    <div class="container">
      <ul class="nav justify-content-between">
  
        <ng-template id="drop1" #notLogged>
          <div class="group-left d-flex">
  
            <li class="nav-item dropdown">
              <div ngbDropdown class="d-inline-block">
                <a class="nav-link dropdown-toggle" id="dropdownForm1" role="button" data-toggle="dropdown"
                  aria-haspopup="true" aria-expanded="false" ngbDropdownToggle>
                  <i class="fas fa fa-user"></i> Login
                </a>
                <div ngbDropdownMenu aria-labelledby="dropdownForm1" class="dropdown-menu drop-adjust">
                  <form class="px-4 py-3" action="" method="POST" enctype = "multipart/form-data" role="form" [formGroup]="form">
                    <div class="form-group">
                      <label for="username">Username</label>
                      <input type="text" class="form-control" id="Username" aria-describedby="username"
                        placeholder="Enter Username" formControlName = "logid">
                      </div>
                    <div class="form-group">
                      <label for="password">Password</label>
                      <input type="password" class="form-control" id="password" aria-describedby="email"
                        placeholder="***********" formControlName = "logpass">
                    </div>
                  </form>
                </div>
              </div>
            </li>
          </div>
        </ng-template>
      </ul>
    </div>
  </section>

I want to navigate from component A to division dropdownForm1 of Component B. How can I get to it?


Solution

  • Simpler/better answer:

    OK, so after your comment I did more reading about this, and it seems that you're not the only one seeing it not working. There are at least these two issues (1 & 2) that could prevent it from working for conditional templates (for e.g. with *ngIf), as I know you have in your project.

    So let's forget about what we did in the initial answer, i.e remove all the stuff with Router configuration since it's not needed, and instead make your ComponentB class look like this:

    import { ViewportScroller } from '@angular/common';
    import { AfterViewInit, Component } from '@angular/core';
    import { ActivatedRoute } from '@angular/router';
    import { first } from 'rxjs/operators';
    
    @Component({
      templateUrl: './b.component.html'
    })
    export class BComponent implements AfterViewInit {
      constructor(
        private route: ActivatedRoute,
        private viewportScroller: ViewportScroller
      ) {}
    
      ngAfterViewInit(): void {
        this.route.fragment
          .pipe(first())
          .subscribe(fragment => this.viewportScroller.scrollToAnchor(fragment));
      }
    }
    

    This should do the trick! I have created this stackblitz angular app for testing it: https://stackblitz.com/edit/angular-q3pydk?file=src/app/app-routing.module.ts.


    Initial generic answer, based on Router Options:

    There are a few steps needed in order to achieve this, nothing too complicated. But first of all just a small note about your html template:

    Do not use <ng-template> like this, since the content of a ng-template is not rendered until someone references that template (for e.g. by using *ngIf=".. ; else notLogged"). If you do have this already in your code, then all's good.

    Another thing is that when referenced, only the content of a ng-template gets added to the DOM, not the <ng-template> itself, since that's not a HTML element. Which means that if you put an id="..." attribute on it, it will get lost. In this case, it means that you need to take id="drop1" out of the ng-template tag and move it on the div below it, i.e.:

    <ng-template #notLogged>
      <div id="drop1" class="group-left d-flex"
    

    Ok, now on the actual navigation. You need to follow the steps below to make it work:

    a) you need to set up the angular router properly for this to work as expected (by default this type of fragment URL navigation is disabled, btw).

    const routerOptions: ExtraOptions = {
        scrollPositionRestoration: 'enabled',
        anchorScrolling: 'enabled',
        scrollOffset: [0, 64],
      };
    
    const routes: Routes = [
    ...
    ];
    
    @NgModule({
      imports: [CommonModule, RouterModule.forRoot(routes, routerOptions)],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
    

    b) now that the router configuration is right, you can do a fragment URL navigation either from a html template:

    <a [routerLink]="'/componentB'" fragment="drop1">Go to section!</a>
    

    or, as in your question, from a component's code:

    this.router.navigate(['/componentB'], {fragment:'drop1'});
    

    For more info, check out this article.