3

I have a menu bar that contain a list of menus loaded from express API and every menu is referenced to a page that have an alias which will be the URL of that page. I am trying to load the page when I click to menu, it's done but only when I refresh the page.

this my menu code:

export class MenuList implements OnInit {

    menus:Menu[];
    menu:Menu;
    page:Page;

    constructor(private router:Router,
                private menuService:MenuService) {
    }

    getMenus():void {
        this.menuService.getMenus()
            .subscribe(
                menus => this.menus = menus, //Bind to view
                err => {
                    // Log errors if any
                    console.log(err);
                }
            );
    }

    getPage(id):void {
        this.menuService.getPage(id)
            .subscribe(
                page => this.page = page, //Bind to view
                err => {
                    // Log errors if any
                    console.log(err);
                });
    }

    ngOnInit():void {
        this.getMenus();
    }

}

and this is my template menu

<nav class="navbar navbar-default">

    <div class="container-fluid">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="navbar"  style="background-color: #97455f">
            <div class="navv">
                <ul *ngFor="let menu of menus">
                    <li class="col-lg-1 col-md-1 col-xs-12 col-sm-12"><a [routerLink]="[menu.page.alias]">{{menu.title}}</a></li>


                </ul>
            </div>
        </div>

    </div><!-- /.navbar-collapse -->
</nav>
<router-outlet ></router-outlet>

I think the problem is in the ngOnInit of my page component, it's not called

    @Component({
    selector: 'page',
    templateUrl: './page.component.html'
})
export class PageComponent implements OnInit {
    alias: string;
    page:Page;

    constructor(private router:Router,
                private route: ActivatedRoute,
                private pageService:PageService) {

        this.route.params.subscribe(
            (params : Params) => {
                this.alias = params["alias"];
                console.log(this.alias)
            }
        );
    }

    


    ngOnInit():void {
        debugger;
        this.pageService.getPage(this.alias).subscribe(page => {
            this.page = page;
            console.log(this.page);
        });
    }

}

and this is my page template

    <p *ngIf="page" [innerHTML]="page.content" ></p>

this is my app routing code

const routes: Routes = [
    { path: '', redirectTo: '/home', pathMatch: 'full' },
    { path: ':alias', component: PageComponent },
    { path: 'archived',  component: ArchivedComponent },
    { path: 'home',  component: HomeComponent },
    { path: 'menu',  component: MenuList },
    { path: 'detail/:id', component: ActualiteDetailComponent },
    { path: 'contact',  component: ContactComponent },

];

@NgModule({
    imports: [ RouterModule.forRoot(routes) ],
    exports: [ RouterModule ]
})
export class AppRoutingModule {}

this is my app component

@Component({
  selector: 'my-app',
  template: `
    <menu-list></menu-list>
    <hr>
`

})
export class AppComponent {

}

Home of application with the menu bar

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Ilyes Atoui
  • 474
  • 2
  • 9
  • 29
  • By the way. Routes order matters. Does not any route in your app goes through `PageComponent `? Even home, menu or contact for example. I mean more specific route should be at the top and more broad below. – Sharikov Vladislav Aug 24 '17 at 14:59
  • 2
    I'm not able to derive from your question what code/html snipped belongs to what component nor what route name `menu.page.alias` might return. – Günter Zöchbauer Aug 24 '17 at 14:59
  • Sharikov Vladislav , yep , all menu url pass from the alias to the PageComponent, my problem that the content of the page is not loaded when i click in menu list but when i refresh the page , it's loaded – Ilyes Atoui Aug 24 '17 at 15:05

4 Answers4

20

Here is a code example of what Gunter is talking about:

  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
     this.route.params.subscribe(
     params => {
        let id= +params['id'];
        this.getProduct(id);
     });
  }

This code watches for changes to the parameters and executes any code inside the arrow function.

DeborahK
  • 57,520
  • 12
  • 104
  • 129
  • From the link you provided: `subscribe will only take one argument: either the next handler (a function) or an observer object.` I'm only passing one argument, so the above syntax should still be fine. – DeborahK Apr 07 '21 at 22:40
  • Is this the only solution? routerLink and router.navigate both does not call the `ngOnInit` In my case I just need call in ngOnint no param thing – Sunil Garg Aug 30 '21 at 13:33
7

When only a router parameter is changes but the base of the route stays the same, Angular reuses the component. ngOnInit() is only called once after a component is instantiated, but not when the route changes.

You can inject the router and subscribe to it's events or params to get notified about route changes.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • 1
    yes but how ? should i use some thing else in the place of ngOnInit? resolver for example ? – Ilyes Atoui Aug 24 '17 at 15:08
  • 1
    You can inject `route:ActivatedRoute` and subscribe to `route.subscribe(...)` – Günter Zöchbauer Aug 24 '17 at 15:19
  • 1
    Ups, I forgot `route.**params**.subscribe. Deborah shows the full code anyway. I think her answer at least earns at least an up-vote ;-) Glad to hear you could make it work anyway. – Günter Zöchbauer Aug 24 '17 at 15:35
  • thanks, but this is strange, most of the time on every page there are api calls that loads th e data, what is the use case of this that angular will not call the ngOnInit if I am using `routerLink` – Sunil Garg Aug 30 '21 at 13:29
  • @SunilGarg I don't think there is a specific usecase, it's just how lifecycles are defined. ngOnInit is called once after the ngOnChanges was called the first time https://angular.io/guide/lifecycle-hooks – Günter Zöchbauer Aug 31 '21 at 07:41
  • @GünterZöchbauer yes ngOnInit is called once, but using navigation as component is re-rendered then hooks should be called, and can you please answer, i have added details on this https://stackoverflow.com/questions/68985216/navigation-of-page-does-not-call-the-ngonint-of-routed-page-angular – Sunil Garg Aug 31 '21 at 08:53
  • 1
    @SunilGarg but it is not re-rendered (there really isn't such a thing). `ngOnInit` is component lifecycle and `onActivate` is a router lifecycle. They are not connected. I understand that you wish they were. Router is separate module and component lifecycle isn't even aware of its existence. That would cause awkward dependencies. – Günter Zöchbauer Aug 31 '21 at 10:49
  • @GünterZöchbauer can you check above question that i mentioned in previous commemt, router event is not working for me as well – Sunil Garg Sep 01 '21 at 04:45
0

Well it fixed thanks to @Günter Zöchbauer and @DeborahK I changed the Page Component code from this

@Component({
selector: 'page',
templateUrl: './page.component.html'
    })
    export class PageComponent implements OnInit {
        alias: string;
        page:Page;

        constructor(private router:Router,
                    private route: ActivatedRoute,
                    private pageService:PageService) {

            this.route.params.subscribe(
                (params : Params) => {
                    this.alias = params["alias"];
                    console.log(this.alias)
                }
            );
        }

    ngOnInit():void {
            debugger;
            this.pageService.getPage(this.alias).subscribe(page => {
                this.page = page;
                console.log(this.page);
            });
        }
    }

to this one

@Component({
selector: 'page',
templateUrl: './page.component.html'
    })
    export class PageComponent implements OnInit {
        alias:string;
        page:Page;

        constructor(private router:Router,
                    private route:ActivatedRoute,
                    private pageService:PageService) {

            this.route.params.subscribe(
                (params:Params) => {
                    this.alias = params["alias"];
                    this.pageService.getPage(this.alias).subscribe(page => {
                        this.page = page;
                        console.log(this.page);
                    });
                    console.log(this.alias)
                }
            );
        }
         ngOnInit():void {
            this.pageService.getPage(this.alias).subscribe(page => {
                this.page = page;
                console.log(this.page);
            });
        }
    }
Lahiru Mirihagoda
  • 1,113
  • 1
  • 16
  • 30
Ilyes Atoui
  • 474
  • 2
  • 9
  • 29
  • 1
    Glad it is working for you. Consider moving the code from the constructor to the ngOnInit. Code to get data should not be in a constructor. Plus you don't need to repeat the getPage method call in your ngOnIt. – DeborahK Aug 24 '17 at 17:39
  • Oh! Yeah. I forgot to delete it. Thanks – Ilyes Atoui Aug 24 '17 at 21:06
0
import { Router } from '@angular/router';
...
export class SettingViewComponent implements OnInit {

 constructor(
   private router: Router
 ) { }

 public ngOnInit(): void {
    this.router.routeReuseStrategy.shouldReuseRoute = () => false;
}
Tariq
  • 188
  • 1
  • 15