Lesson Tuesday

An important part of any application is interactivity. For instance, our To Do List users will want to be able to add and delete Tasks.

In this lesson, we'll add interactivity to our views by using an event binding. We'll add an edit button to our To Do List application to test this new concept. For now the button will trigger an alert message. In the next lesson, we'll cover two-way binding and add an edit form.

Interactivity with jQuery

In Intro to Programming, we managed the interactive portions of our sites with jQuery. We attached listeners to elements that needed to be interactive and executed JavaScript and jQuery when buttons were clicked or forms submitted. Here's an example from Intro:

$(".clickme").click(function(){
   $(".walrus").show(); 
});

The problem with jQuery click and event handlers is that as our apps grow in complexity, our jQuery code grows and gets much more difficult to manage and organize.

However, we won't be required to use jQuery this way in Angular. Angular includes built-in capabilities to recognize events and perform specific actions when they occur.

Angular Interactivity with Event Bindings

Angular handles interactivity using event bindings. Similar to jQuery listeners like the one above, we can attach an event binding to any DOM event (such as a form submission or button click). When that event occurs, we can trigger specific code to run.

Anatomy of an Angular Event Binding

A basic event binding looks something like this:

<button (click)="someMethod()">Click me!</button>

It's composed of three primary parts:

  • The HTML element it is attached to. In the example above, the event binding is attached to a <button>. You can add event bindings to almost any HTML tag.

  • The target event. This is the event that must occur to trigger our code. In the example above, it is click. The target event is always represented by the name of the specific DOM event between parentheses. (We'll discuss other DOM events we can include here at the end of this lesson.)

  • A template statement. In the example above, someMethod() is our template statement. The template statement is a method call or property assignment that runs when the target event occurs.

Event Binding in To Do List

Now that we have a basic understanding of the structure and purpose of event bindings, let's add one to our ongoing To Do List application. Eventually, we'll want to edit and update our existing Task objects. Let's add functionality that allows us to select a Task to edit by clicking on it. When clicked, an edit form will appear.

We'll modify our root component's template to include an event binding.

app/app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
 template: `
    <div class="container">
     <h1>To Do List for {{month}}/{{day}}/{{year}}</h1>
     <h3>{{currentFocus}}</h3>
     <ul>
       <li *ngFor="let currentTask of tasks">{{currentTask.description}}   <button (click)="editTask()">Edit!</button></li>
     </ul>
   </div>
  `
})

...

In the code above, we've added an HTML <button> element with an attached event binding. The event binding's target event is click, and its template statement is editTask(). When this button is clicked, a method called editTask() will be triggered.

Event bindings should reside in the template areas of components. When the specified event occurs, Angular will look for a method matching the target event in that component's class declaration.

When the "Edit" <button> in the template of our component registers a click event, Angular will run the editTask() method defined in that same component's class declaration.

Let's define this method now. For now, let's simply pop up an alert to confirm our event binding is working.

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();
  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')
  ];

  editTask() {
    alert("You just requested to edit a Task!");
  }
}

export class Task {
  public done: boolean = false;
  constructor(public description: string) {  }
}

Notice the editTask() method is not within the Task class. Template statements (the methods event bindings trigger) must be defined in the component class (in this case, our AppComponent).

Remember, the template (or front-end) of the component defines how a component appears to the user while the class declaration (the back-end) of the component determines how it behaves.

If we launch our application, we should see new edit buttons next to each Task.

task-edit-buttons

If we click one of the buttons, our alert should appear.

event-binding-triggering-alert

Event bindings are a very important part of Angular and can be very complex. Let's review what occurs when an event binding is triggered before we expand these concepts further in the next lesson.

  1. We attach an event binding to an HTML element: <button (click)="editTask()">Edit!</button>. It includes a target event of click and the template statement editTask().

  2. When the target event occurs (the button registers a click), Angular takes the method from the template statement and looks for an editTask() method in this component's class declaration (the AppComponent class).

  3. The logic in the editTask() method is executed, triggering an alert:

...
  editTask() {
    alert("You just requested to edit a Task! ");
  }
...

Let's explore one more example. What if we also wanted to click any individual Task to see whether it has been completed? We could add another event binding on the <li> that contains the Task description.

app/app.component.ts
...
template: `
    <div class="container">
     <h1>To Do List for {{month}}/{{day}}/{{year}}</h1>
     <h3>{{currentFocus}}</h3>
     <ul>
       <li (click)="isDone(currentTask)" *ngFor="let currentTask of tasks">{{currentTask.description}}  <button (click)="editTask()">Edit!</button></li>
     </ul>
   </div>
  `
})
...

You'll notice that the <li> now contains both the *ngFor directive and the new event binding. You can add multiple pieces of Angular syntax to a single element. This means each <li> produced in the loop will have its own event binding.

You'll also notice we pass currentTask as an argument to the isDone() template statement. Just like any other method, template statements may accept arguments.

Let's define the corresponding isDone() method in the back-end of the component, too. This is the method that will run when the <li> registers a click event:

app/app.component.ts
...
export class AppComponent {
  ...

  editTask() {
    alert("You just requested to edit a Task! ");
  }

  isDone(clickedTask: Task) {
    if(clickedTask.done === true) {
      alert("This task is done!");
    } else {
      alert("This task is not done. Better get to work!");
    }
  }

}
...

If we refresh the page and click any Task, we should see a new alert.

is-done-alert

None of the Tasks are complete yet because they all have a default done value of false. We'll add the ability to change their done property from false to true in an upcoming lesson.

This process changes the model from the view. The two are bound together and the model reflects an intention captured from the view.

More Event Bindings

Using the same basic formula depicted in this lesson, you can create an event binding for nearly any occasion.

Any DOM event is an Angular target event. You can find a list of all DOM events in the Event Reference entry of the Mozilla Developer Network's JavaScript documentation. These events include everything from submit to mouseover and even actions like copy and paste.

Additionally, an event binding can be attached to any standard HTML element and we can execute TypeScript and JavaScript (plus some Angular-specific stuff we'll address later) in an event binding's template statement. The possibilities are endless!

Experiment using different events on different HTML elements as you develop your Angular applications these next few weeks. You might be surprised by the wide variety of things you can accomplish using only event bindings.

In the next lesson, we'll discuss another type of Angular 2 data binding known as two-way event binding. We'll use this to add an edit form to our To Do List application.

For more information on event bindings, check out the Event Binding entry of the Angular 2 documentation.


Example GitHub Repo for Angular 2 To Do List