Lesson Thursday

Creating a New Component

Let's use Angular CLI to generate our new TaskListComponent:

$ ng generate component task-list

Component file names should always be all lowercase and describe the purpose of the component. Multiple-word names should include hyphens between words. Every component file should end in .component.ts (the CLI will take care of this part for us).

Angular CLI will do the following:

create src/app/task-list/task-list.component.css (0 bytes)
create src/app/task-list/task-list.component.html (28 bytes)
create src/app/task-list/task-list.component.spec.ts (643 bytes)
create src/app/task-list/task-list.component.ts (280 bytes)
update src/app/app.module.ts (472 bytes)

The CLI has generated four new files in a new task-list directory inside of app. These files look very similar to our root component. Note that there is some new code in task-list.component.ts referring to onInit. This is code that will run when the component is initialized. We will be covering this in a future lesson but don't worry about it just yet.

Note also that the CLI has updated app.module.ts. Our new component is already imported and declared! This may not seem like a big deal, but in the past developers had to add all these files manually and update the root module with each new component. The CLI adds a great deal of convenience for Angular users.

Implementing a New Component

Let's move code responsible for displaying the list of Tasks from our AppComponent root component into our new TaskListComponent.

First, we'll move the <ul> containing the list of Tasks from our app.component.html to our task-list.component.html:

app/task-list/task-list.component.html
<ul>
  <li [class]="priorityColor(currentTask)" *ngFor="let currentTask of tasks">{{currentTask.description}} <button (click)="editTask(currentTask)">Edit!</button></li>
</ul>

(Don't forget to remove this code from the root component's HTML template as well!)

Now let's make sure to include the tasks array this component will be responsible for listing along with any methods the code above calls (with the exception of the editTask() method, which will go inside our EditTaskComponent). Here's what the class declaration of task-list.component.ts should look like now:

app/task-list.component.ts
...
export class TaskListComponent {
  tasks: Task[] = [
    new Task('Finish weekend Angular homework for Epicodus course', 3),
    new Task('Begin brainstorming possible JavaScript group projects', 2),
    new Task('Add README file to last few Angular repos on GitHub', 2)
  ];

  priorityColor(currentTask){
    if (currentTask.priority === 3){
      return "bg-danger";
    } else if (currentTask.priority === 2) {
      return  "bg-warning";
    } else {
      return "bg-info";
    }
  }
}

(The code referring to onInit has been removed. It's fine to keep it there but we might as well remove it if we don't need it.)

Now that our new component is using Tasks, it needs access to the Task model. We need to import it:

app/task-list.component.ts
import { Task } from '../models/task.model';

Note that the path is slightly different now: we need to go up a level using ../ so our component can find the models directory.

The class declaration of our root component should now look like this:

app/app.component.ts
...
export class AppComponent {
  currentFocus: string = 'Angular Homework';
  currentTime = new Date();
  month: number = this.currentTime.getMonth() + 1;
  day: number = this.currentTime.getDate();
  year: number = this.currentTime.getFullYear();
  selectedTask = null;

  editTask(clickedTask) {
    this.selectedTask = clickedTask;
  }

  finishedEditing() {
    this.selectedTask = null;
  }
}

There's only one problem. If we serve our application, our list of tasks is no longer rendering. Remember how each component has a selector? We need to place our new component's selector tag where we want the list of tasks to be rendered.

We'll put the tag inside our root component's HTML template because that's where the list of tasks was rendered previously. Take a look at our new component's class annotation and you'll see the selector is app-task-list. While you are welcome to rename the selector, we'll keep Angular CLI's suggestion for now:

app/app.component.html
...
<h1>To Do List for {{month}}/{{day}}/{{year}}</h1>
<h3>{{currentFocus}}</h3>
<app-task-list></app-task-list>
...

If you refresh the page, the list of tasks should be showing again! We've successfully separated out our list of tasks into a new component. However, our edit button is no longer working. The console politely informs us "editTask is not a function".

This is expected behavior. Our TaskListComponent still contains an event binding to call editTask(), but we haven't moved editTask() from the root component into TaskListComponent. That's because we'll be moving it to a dedicated EditTaskComponent over the next few lessons.