0

I have created a Angular 7 web app data-driven display of navigation items and content to be shown when a nav item is selected.

I have the following nav item interface:

interface NavItem {
  title: string;
  icon: string;
  link: string;
  pages?: NavItem[];
}

Where it can be implemented like so for an Angular route:

title: 'Home',
icon: 'faCoffee', // from Material CSS
link: '/home', // Notice it is an Angular route
pages: null

Or like this:

title: 'Company Name',
icon: 'faCompany',
link: 'http://subdomain.company.com', // Notice it is an external URI
pages: null

I have the following in nav.component.html:

<div *ngFor="let navItem of navItems">     

<!-- use a simple div for an item that has no children,
        match up the styling to the expansion panel styles -->
      <div class="nav-head" *ngIf="navItem.pages === null">
        <a class="nav-link"
          (click)="changeLink(navItem.link)" // (1)
          routerLinkActive="selected">
          <mat-icon>{{navItem.icon}}</mat-icon>
          <span class="nav-link-text">{{navItem.title}}</span>
        </a>
      </div>
    </div>

<app-content-display [hyperlink]="rawLink"></app-content-display> // (2)

In nav.component.ts

export class NavComponent {
  rawLink: string = "/";

  public navList: NavItem[];

  changeLink(link: string){ // (1)
    this.rawLink = link;
  }
}

app-content-display directive is defined like so:

content-display.component.ts:

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

  private _link = '';
  isAngularLink = true;

  @Input()
  set hyperlink(hyperlink: string){ // When a setter is triggered by (1), the value is checked to determine if it is an Angular route. The output then decides whether to show an angular router-outlet or to show an iframe.
    this._link = hyperlink;
    this.isAngularLink = this.checkIfAngularLink();

    if(this.isAngularLink){
      this.router.navigate([`${this._link}`]);
    }
  }

  get hyperlink(): string{
    return this._link;
  }

  trustedLink = () => {
    return this.sanitizer.bypassSecurityTrustResourceUrl(this.hyperlink); // Has to be a function as opposed to a property that gets
  } 

  constructor(private sanitizer: DomSanitizer, private router: Router ) {  }

  ngOnInit() {}

  checkIfAngularLink(){

    if(this._link.indexOf('company.com') > 0){
      return false;
    }

    return true;
  }
}

On content-display.component.html:

<div *ngIf="isAngularLink">
  <router-outlet></router-outlet>
</div>

<div *ngIf="!isAngularLink">
  <iframe [src]="trustedLink()" width="100%" height="800px"></iframe>
</div>

The end result is:

The parent component (nav.component) shows a child component (content-display.component). When a link is clicked on parent component, the child component's hyperlink property receives the link, checks if it is an Angular route vs external resources.

  1. If a user clicks on a navigation link that points to an internal Angular page, router-outlet will show the output
  2. If a user clicks on a navigation link that points to an external URI, an iframe will be called to show the output.

I feel that child component (content-display.component) may know (i.e. not obeying SRP) and do too much and may need refactoring. However, I don't anticipate child component will be reused by other areas of the web app. Any thoughts on the architecture of my navigation components?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.