Angular
Building RealWorld, Production-Quality Apps with Angular
  •  

How To: Basic Page Layout and Routing

PRO

I finished! On to the next chapter

Outline

Before we get started, we need to get the seed project up and running on your computer.

Clone the project from Github:
git clone git@github.com:gothinkster/angular2-realworld-example-app.git
After the repo is cloned, run npm install to install necessary dependencies.
Checkout the seed branch (which is named m-9)
git checkout m-9

The seed app starts you off with a shared folder that contains the SharedModule and the barrel file index.ts. The SharedModule is imported in app.module.ts to make it available to the app. The seed app was generated using Angular's CLI tool and then we optimized the file structure for our somewhat complicated, large web app.

To begin our project, we need to first build the basic layout and routing for the Conduit application. Specfically, we'll need to set up the router, get a header and footer in place, and create a home page. Lets start with creating the header and footer for the site.

The Angular style guide dictates that we should use a "folder-by-feature" project layout. For example we're going to create our Header and Footer components in a layout folder, and create a Home component in a home folder. This is how Angular enforces seperation of concerns.

Create the FooterComponent. You'll need to create the shared and layout folders as well.

src/app/shared/layout/footer.component.html

<footer>
  <div class="container">
    <a class="logo-font" routerLink="/">conduit</a>
    <span class="attribution">
      &copy; {{ today | date: 'yyyy' }}.
      An interactive learning project from <a href="https://thinkster.io">Thinkster</a>.
      Code licensed under MIT.
    </span>
  </div>
</footer>

We'll need expose the current date through the variable today on the footer's component class. We are using Angular's DatePipe to format the current year.

src/app/shared/layout/footer.component.ts

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

@Component({
  selector: 'layout-footer',
  templateUrl: './footer.component.html'
})
export class FooterComponent {
  today: number = Date.now();
}

Next lets create the header for our site.

Create the HeaderComponent

src/app/shared/layout/header.component.html

<nav class="navbar navbar-light">
  <div class="container">
    <a class="navbar-brand" routerLink="/">conduit</a>

    <ul class="nav navbar-nav pull-xs-right">

      <li class="nav-item">
        <a class="nav-link"
          routerLink="/">
          Home
        </a>
      </li>

      <li class="nav-item">
        <a class="nav-link">
          Sign in
        </a>
      </li>

      <li class="nav-item">
        <a class="nav-link">
          Sign up
        </a>
      </li>

    </ul>

  </div>
</nav>

src/app/shared/layout/header.component.ts

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

@Component({
  selector: 'layout-header',
  templateUrl: './header.component.html'
})
export class HeaderComponent {
  constructor() {}

}
Allow these components to be easily imported across our app via barrels

Creat a barrell file in the layout folder and export both the HeaderComponent and FooterComponent:

src/app/shared/layout/index.ts

export * from './footer.component';
export * from './header.component';

Now create a root barrell file in the shared folder. Export our layout folder for easy access.

src/app/shared/index.ts

export * from './shared-module';
+ export * from './layout';

Perfect! Next lets create our home page. Create a home folder in our app directory.

Create the HomeComponent

src/app/home/home.component.html

<div class="home-page">

  <div class="banner">
    <div class="container">
      <h1 class="logo-font">conduit</h1>
      <p>A place to share your <i>Angular</i> knowledge.</p>
    </div>
  </div>

  <div class="container page">
    <div class="row">

      <div class="col-md-9">
        <div class="feed-toggle">
          <ul class="nav nav-pills outline-active">
            <li class="nav-item">
              <a class="nav-link">
                 Your Feed
              </a>
            </li>
            <li class="nav-item">
              <a class="nav-link">
                 Global Feed
              </a>
            </li>
          </ul>
        </div>


      </div>

      <div class="col-md-3">
        <div class="sidebar">
          <p>Popular Tags</p>


        </div>
      </div>

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

src/app/home/home.component.css

.nav-link {
  cursor:pointer;
}

And we'll import both into the HomeComponent.

src/app/home/home.component.ts

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

@Component({
  selector: 'home-page',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent {
  constructor() {}

}

Our Home component will serve as the base from where to navigate from. The app.module is the root of the app and any other page components we add will be children. Here we declare our base navigation as a child of app.module

Create the HomeModule

src/app/home/home.module.ts

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

import { HomeComponent } from './home.component';
import { SharedModule } from '../shared'; 

const homeRouting: ModuleWithProviders = RouterModule.forChild([
  {
    path: '',
    component: HomeComponent
  }
]);

@NgModule({
  imports: [
    homeRouting,
    SharedModule
  ],
  declarations: [
    HomeComponent
  ],
  providers: []
})
export class HomeModule {}

Now lets put it all together!

Import the HomeModule, HeaderComponent, and FooterComponent into the AppModule and declare the rootRouting for the application

We need to declare the HeaderComponent and FooterComponent in order to use them in the AppComponent's template (coming up in the next step).

src/app/app.module.ts

 import { ModuleWithProviders, NgModule } from '@angular/core';
 import { BrowserModule } from '@angular/platform-browser';
+import { RouterModule } from '@angular/router';

 import { AppComponent } from './app.component';
+import { HomeModule } from './home/home.module';
 import {
   SharedModule,
+  FooterComponent,
+  HeaderComponent,
 } from './shared';

+const rootRouting: ModuleWithProviders = RouterModule.forRoot([], { useHash: true });

 @NgModule({
   declarations: [
     AppComponent,
+    FooterComponent,
+    HeaderComponent
   ],
   imports: [
     BrowserModule,
     SharedModule,
+    HomeModule,
+    rootRouting,

   ],
   providers: [],


[...]

Finally, we just need to place the HeaderComponent and FooterComponent above and below the router-outlet where our routes will get rendered to.

Replace the AppComponent template with our layout components and a router-outlet

src/app/app.component.html

<layout-header></layout-header>

<router-outlet></router-outlet>

<layout-footer></layout-footer>

In your browser, you should now see the home page rendered between the header and footer components!

You can view the working code on Github or checkout the branch locally:

git checkout m-8