0

I'm trying to build an Angular (v6.2.9) based theme for my blogger blog and this is when I encountered this problem. I'm trying to load pages from my blog. For this, I created components and corresponding paths (see the code below). Pages on blogger have the format http://{blogname}.blogspot.com/p/{permalink}. The problem with my current code is that it loads any page perfectly fine for the first time when routerLink with the corresponding matching routes is clicked. But when a link with just different placeholder is clicked, only the URL changes in the address bar but nothing loads on screen.

I tried printing variables onto the console from content.component.ts for debugging, but I get the expected results. The variables get printed just for once. I also tried variations of routerLink with and without [] brackets but no luck. I guess router.navigate() will also not work. Given that, I'm suspecting something is wrong in my design or code.

app.component-html

<app-page></app-page>
<router-outlet></router-outlet>

app-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

import { ContentComponent } from './content/content.component';

const routes = [
  { path: 'p/:permalink', component: ContentComponent }
];

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

page.component.html

<div *ngIf="allPages">
  <div *ngFor="let page of allPages | keyvalue">
    <a routerLink="{{ page.value['url'] }}"> {{ page.value['id']  }}</a>
  </div>
</div>

page.component.ts

import { Component, OnInit } from '@angular/core';

import { BloggerRestService } from '../blogger-rest.service';

@Component({
  selector: 'app-page',
  templateUrl: './page.component.html',
  styleUrls: ['./page.component.scss']
})
export class PageComponent implements OnInit {

  blogInfo = {
    "url" : "http://dkrypted.blogspot.com/"
  }

  allPages: any = null;

  constructor(
    private rest: BloggerRestService
  ) { }


  ngOnInit() {
    this.getPages();
  }

  getPages() {
    this.rest.getAllPages().subscribe( pages => {
      this.allPages = pages["items"];

      for( let page in this.allPages ) {
        let new_url = this.allPages[page]['url'].replace( this.blogInfo['url'], '/' );

        this.allPages[page]['url'] = new_url;
      }

      console.log(this.allPages);
    });
  }

  isEmptyObject( obj ) {
    for(var prop in obj) {
        if(obj.hasOwnProperty(prop))
            return false;
    }

    return true;
  }
}

content.component.html

<div *ngIf='post'>
  <p [innerHTML] = 'post["content"]'></p>
</div>

content.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';

import { BloggerRestService } from '../blogger-rest.service';

@Component({
  selector: 'app-content',
  templateUrl: './content.component.html',
  styleUrls: ['./content.component.scss']
})
export class ContentComponent implements OnInit {

  blogInfo = {
    "url" : "http://dkrypted.blogspot.com/"
  }

  post: any;

  pageParam = {
    'permalink': ''
  }

  constructor(
    private route: ActivatedRoute,
    private rest: BloggerRestService,
    private router: Router
  ) { }

  ngOnInit() {
    this.pageParam['permalink'] = this.route.snapshot.paramMap.get('permalink');

    let path = "/p/" + this.pageParam['permalink'];
    this.getPage(path);
  }


  getPage( path ) {
    let allPages = null;
    let flag = false;

    this.rest.getAllPages().subscribe( pages => {
      allPages = pages["items"];

      console.log(allPages.length);

      if( allPages.length ) {
        for( let page in allPages ) {

          let new_url = allPages[page]['url'].replace( this.blogInfo['url'], '/' );

          if( new_url == path ) {
            flag = true;

            this.rest.getPage( allPages[page]['id'] ).subscribe((page: {}) => {
              this.post = page;
              console.log(this.post);
            });

            break;
          }
        }

        if( !flag )
            this.router.navigate(['/404']);
      }
    });

    console.log("Get Page called!");
  }

}

Here's the link to Blogger API for understanding the JSON structure https://developers.google.com/blogger/docs/3.0/reference/pages

I'm a newbie to Angular and still learning. It might be possible that I would've missed something.

CherryGot
  • 39
  • 8
  • 1
    Have a look at this: https://blog.angularindepth.com/refresh-current-route-in-angular-512a19d58f6e – Stephen R. Smith May 23 '19 at 05:39
  • 1
    I believe it's because you're using a router snapshot and not getting the router observable and subscribing to it. In the ContentComponent ngOnInit, don't use the router.snapshot. Router.params, I believe, is an observable and when the URL changes will emit a new value. Then you can load the new content. – pjlamb12 May 23 '19 at 05:50
  • 1
    Sorry, it's ActivatedRoute that you should inject. Here is an example: (https://github.com/pjlamb12/app-config-editor-client/blob/master/src/app/app-manager/app-details/app-details.component.ts). – pjlamb12 May 23 '19 at 05:54
  • @pjlamb12 Thanks! That worked like charm. Using subscription on router.params solved the issue. – CherryGot May 24 '19 at 11:33
  • 1
    @StephenR.Smith Thanks for sharing the article. It was worth noting the pros and cons of different approaches to solve this problem. – CherryGot May 24 '19 at 11:35
  • @FedUser I'm glad it worked! I posted an answer below if you'd like to accept it! – pjlamb12 May 24 '19 at 15:04

1 Answers1

1

The reason it's not updating when you change the route is because you're using a snapshot of the paramMap to get the permalink route variable. Instead, you should use the ActivatedRoute.params observable. That way, when changes happen to the route, the component will know about them and be able to react.

this.route.params.pipe(
    switchMap(
        (params: Params) => {
            this.pageParam['permalink'] = params['permalink'];
            ...
        }
    )
)
pjlamb12
  • 2,300
  • 2
  • 32
  • 64
  • I am just wondering if I use subscription over pipe, which one will be efficient? What's your preference? – CherryGot May 25 '19 at 04:37
  • You have to use pipe to use the switchMap operator. You can then subscribe after the pipe or you could use an async pipe in the template after setting the this.route.params to a variable. – pjlamb12 May 26 '19 at 05:23