Downloadable Example

You can download the day’s code from resources/courseware-master.zip

Routing

READ: Router

I have set up the courseware site to have a few routes:

/syllabus

The root information about a course

/assignments

The location where we should be able to see assignments

/quizzes

The location where we should be able to see quizzes

Note: these will change on the actual homework because they are somewhat poorly thought out. They serve as an example for now.

app.routing.ts
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';

import { SyllabusComponent } from './syllabus/syllabus.component' (1)
import { AssignmentComponent } from './assignment/assignment.component'
import { AssignmentDetailComponent } from './assignment-detail/assignment-detail.component'
import { PageNotFoundComponent } from './page-not-found/page-not-found.component'

const routes: Routes = [
	{ path: 'syllabus', component: SyllabusComponent }, (2)
	{ path: 'assignments', component: AssignmentComponent },
	{ path: 'assignments/:name', component: AssignmentDetailComponent },
	{ path: '',
		redirectTo: '/syllabus', (3)
		pathMatch: 'full'
	},
	{ path: '**', component: PageNotFoundComponent }
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
1 Import all components to reference
2 Set a path for each component
3 Set a root and default path
app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule }    from '@angular/common/http';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { FormsModule } from '@angular/forms';

import { AppRoutingModule } from './app-routing.module'; (1)
import { AppComponent } from './app.component';
import { SyllabusComponent } from './syllabus/syllabus.component';
import { AssignmentComponent } from './assignment/assignment.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
import { AssignmentDetailComponent } from './assignment-detail/assignment-detail.component';

@NgModule({
  declarations: [
    AppComponent,
    SyllabusComponent,
    AssignmentComponent,
    PageNotFoundComponent,
    AssignmentDetailComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule, (2)
	HttpClientModule,
	NgbModule,
	FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {
	selectedCourse: string;

	setActive(course: string) {
		this.selectedCourse = course;
	}
}
1 We must import our router
2 We must let angular know to use our router
app.component.html
<div class="container">
<h1>Campus</h1>

<ul class="nav">
  <li class="nav-item">
    <a class="nav-link" routerLink="/syllabus" routerLinkActive="active">Syllabus</a> (1)
  </li>
  <li class="nav-item">
    <a class="nav-link" routerLink="/assignments" routerLinkActive="active">Assignments</a>
  </li>
  <li class="nav-item">
    <a class="nav-link" routerLink="/quizzes">Quizzes</a>
  </li>
</ul>

<router-outlet></router-outlet> (2)
</div>
1 include a routerLink for every path we wish to link
2 include <router-outlet> to be replaced with the selected component

Data services to the rescue

A data service is really just a common library in Angular for all components to request. We can use dependency injection to request any particular service be injected into our component.

ng generate service syllabus-data Let’s build a service to store our syllabus data!

models/syllabus-data.service.ts
import { Injectable } from '@angular/core';
import { Course } from './Course';

@Injectable({ (1)
  providedIn: 'root'
})
export class SyllabusDataService {
	public courses: Course[] = [ (2)
		{
			"section": "P422",
			"title": "Web Enterprise Systems",
			"description": "Client/Server web technologies",
			"gradingScale": [
				"90-100: A",
				"0-89: F"
			],
			"calendar": [
				"1: NodeJS",
				"2: Angular",
				"3: ???",
				"4: PROFIT!"
			],
			"bookInfo": "Node.js, MongoDB, and Angular Web Development",
			"meetingTime": "M/W 19:30-21:20",
			"universityInfo": "Don't cheat."
		}
	];

  constructor() { }

  public find(name: String): Course { (3)
	let res = this.courses.find(c => c.section.toLowerCase() === name.toLowerCase());
	if (!res) {
		return null;
	}
	return res;
  }
}
1 We must make this service injectable to use it in a component (note the import above)
2 courses will be accessible from outside of this service as it is public
3 This find method will be accessible, which would allow us to make courses private

How do we use this from outside of the injectable?

syllabus/syllabus.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { SyllabusDataService } from '../models/syllabus-data.service';
import { Course } from '../models/Course';

@Component({
  selector: 'app-syllabus',
  templateUrl: './syllabus.component.html',
  styleUrls: ['./syllabus.component.css']
})
export class SyllabusComponent implements OnInit {
  @Input() selectedCourseName: string;
  selectedCourse: Course;

  constructor(
	private syllabusDataService: SyllabusDataService
  ) { }

  ngOnChanges() {
	  selectCourse(this.selectedCourseName);
  }

  selectCourse(course) {
	  this.selectedCourse = this.syllabusDataService.find(course) || null;
  }

}
syllabus/syllabus.component.html
<div *ngIf="selectedCourse">
<h2>{{selectedCourse.section}}: {{selectedCourse.title}}</h2>

<div><span class="inline-title">Description:</span> {{selectedCourse.description}}</div>
<div><span class="inline-title">Book Info:</span> {{selectedCourse.bookInfo}}</div>
<div><span class="inline-title">Meeting Time:</span> {{selectedCourse.meetingTime}}</div>

<div class="title">Calendar</div>
<table>
	<tr *ngFor="let day of selectedCourse.calendar">
		<td>{{day}}</td>
	</tr>
</table>

<div class="title">Grading Scale</div>
<table>
	<tr *ngFor="let grade of selectedCourse.gradingScale">
		<td>{{grade}}</td>
	</tr>
</table>

<div class="title">University Information</div>
<p>{{selectedCourse.universityInfo}}</p>

</div>
<div *ngIf="!selectedCourse">
No course selected.
</div>

Neat! Now whenever the input changes, we will request the course data from the SyllabusDataService.