Lesson Monday

Our to do application now has a Task model and we can dynamically display variables. However, we're still manually inserting each new Task into the HTML:

app/app.component.html
...
     <h3>{{currentFocus}}</h3>
     <ul>
       <li>{{firstTask.description}}</li>
     </ul>
   </div>
  `
...

This isn't very efficient. Angular has a set of built-in tools called directives that allow us to add loops, conditionals, and other functionality directly into our templates.

Introduction to Directives

In Angular, a directive is a function embedded directly into the template that can dynamically change the way the DOM appears. Much like a director directs the actors on the set of a movie, an Angular directive directs the appearance and structure of the DOM on the fly.

There are three types of directives in Angular:

  • Structural Directives: These change the structure of the DOM by adding and removing elements. (This is similar to how we added and removed elements using the jQuery .append() and .remove() methods in Intro to Programming).

  • Attribute Directives: These change the appearance or behavior of an element in the DOM (for instance, we can dynamically add or remove CSS styles).

  • Components: Components are directives, too. They can be dynamically rendered in the DOM and alter the DOM's appearance.

This lesson will focus on structural directives. We'll cover the other types of directives in future lessons.

Structural Directives

When we learned basic JavaScript in Intro to Programming, we often wrote code that looked like this:

example-javascript-to-do-list.js
$(document).ready(function() {

    var tasks = ['Finish weekend Angular homework for Epicodus course', 'Begin brainstorming possible JavaScript group projects', 'Add README file to last few Angular repos on GitHub'];

    tasks.forEach(function(currentTask) {
       $(".to-do-list").append(currentTask);
    });
});

The code above loops through the tasks array, using jQuery to append each array element to the to-do-list class.

However, jQuery can be very finicky. In addition, jQuery often leads to what's called "spaghetti code" in larger applications, which is exactly what it sounds like: code that's tangled and messy like spaghetti!

The ngFor Repeater Directive

Fortunately, Angular has a directive that makes this kind of looping much easier. Let's replace our firstTask property with an array of tasks in our root component's AppComponent class.

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

We've created a tasks property and declared that it will contain an array of Task objects. We've also moved the one task we have so far into the array and added a few more tasks as well. (We've also removed the firstTask property, which isn't shown here.)

Now let's use Angular's repeater directive to loop through our Tasks in the template:

app/app.component.html
<h1>To Do List for {{month}}/{{day}}/{{year}}</h1>
<h3>{{currentTask}}</h3>
<ul>
  <li *ngFor="let currentTask of tasks">{{currentTask.description}}</li>
</ul>

Pay careful attention to the <li> tag. It now reads <li *ngFor="let currentTask of tasks">. This is our directive. Let's break down this new syntax:

  • *ngFor is Angular's repeater directive. By adding this directly to the <li> tag, we are establishing this <li> element as the repeater template. We're instructing Angular to make an additional copy of this <li> for each item in our list. We can make any element the repeater template simply by adding the directive to its tag.

  • With "let currentTask of tasks", we're essentially doing the following:

tasks.forEach(function(currentTask) {})

The "let currentTask of tasks" syntax is also very similar to functionality in ES6 which we haven't covered: the for of loop.

If we refresh the the browser, we'll see that the repeater directive has appended each task to an <li> element in the DOM.

angular-repeater-directive-in-action

Directives can be used to hide or show areas of the DOM using a conditional statement, dynamically add or remove CSS classes, and more. You can even define your own custom directives. As our applications grow in size, we'll learn more directives to manage dynamic, on-the-fly changes to our DOM.

For more information, check out the Angular Documentation for Structural Directives.