Angular Structural Directives

Angular Structural Directives

When building a user interface using Angular, we need a valid template defined either inline, or in a dedicated html file. The template itself is created using html, and in order to give that html special powers, Angular data binding and directives are used. Angular makes it easier to build out these user interfaces since data binding provides for dynamic data to be displayed and events allow the Angular application to respond appropriately to user actions. Angular directives provide the ability to add logic to html, which is something that it does not have by default.

Advantages of an Inline Template

So far, we have started by creating an inline template in the app.component.ts file. While not always the best option, there are some advantages.

  • The template is defined directly inside the associated component
  • Keeps the view and the code for that view in one spot
  • Makes matching up data bindings to class properties easier

Building A Linked Template

Even with the advantages listed above, it often makes sense to use a Linked Template instead. Inline templates do not work as well with various IDE development tools such as Visual Studio Code, Jetbrains Webstorm, and others. Often intellisense like features and automatic formatting won’t work. So as the amount of html required increases, it becomes easier to leverage that linked template approach. Let’s build a component that can list video games.

Building A Game List Component

By convention, it makes sense to create dedicated folders to hold each component. As such, we can first create a games folder to hold the games related component.
new directory to hold angular component

Now let’s add the template for the games list component in that new folder. It will be named game-list.component.html.
create new angular template file

In our template file, the following html can be used to get started building a layout to display some games.

The template file is now in place. The next thing to do is to create the component itself. We will name it game-list.component.ts.
angular typescript file

The following Typescript code will import the Component decorator from Angular core, define the selector, link to the template we just created using the templateUrl property, and lastly set up a simple pageTitle property so we can use that data in the view.

If your IDE gives you a message such as ng: Component ‘GameListComponent’ is not included in a module and will not be available inside a template. Consider adding it to a NgModule declaration, don’t worry we will fix that soon.

Using a Component As A Directive

When a component has a selector defined like we did above using games-list, we can use the component as a directive. What does that mean? It means we can use the games-list selector as an html element in any other component’s template. So to put the game-list.component.html template inside of app.component.ts for example, we can do so like this.

Configuring The Angular Module

In order to use a component as a directive, Angular needs to know how to render that custom html element. In order for this to happen, the Angular Module that is associated with this component needs to be configured. Every angular application needs to have at least one angular module and this is usually the AppModule. A component needs to belong to only one Angular Module. So when a component contains a directive, Angular looks at that components module to see what directives are visible to that component. This means we need to either declare or import that component in the AppModule.

Test The Application

Ok! With all that legwork out-of-the-way, we can fire up the application and see what we get. Navigate to the root directory of your project and run the ng serve command. When we visit the application in the browser, it looks like we were able to get our custom directive working! We have used the game-list component as a directive.
angular custom directive

Adding Dynamic Data

Right now there is only static data in the application. Let’s change that by using data binding. The first thing we can do is to visit the game-list.component.html file and remove the hard-coded page title and replace with an interpolation such as {{pageTitle}}.

Now in the game-list.component.ts file, we can set that property. We’ll set it to Dynamic! Game List just so that it is something different from the hard-coded value we had earlier.

If we re visit the application, it should now display the data for that pageTitle variable, and it does!
angular one way interpolation

Introducing Angular *ngIf

We learned that a directive is a custom html element or attribute which has special powers beyond normal html. Directives are both custom and built-in. The *ngIf directive is one such built-in angular directive. It is used to add logic to the html, and is also known a structural directive. This is because it has the ability to modify the layout or structure of a template by adding, removing, or otherwise manipulating elements and their children. If an angular directive begins with an asterisk (*), then you know it is a structural directive. Let’s see this in action.

We only want to display the table that displays games, when there are games to display. If there are no games, then there is no sense in displaying the table. So to simulate having no games to display, we will create a games property in the game-list.component.ts file and set it to an empty array.

Now, in the actual template file we can use that *ngIf to check if there are any games available to display. What this will do is allow the <table> element to appear or disappear based on that condition.

Since there are no games to display, then the table should no longer appear. Looks good!
angular ngif example

Introducing Angular *ngFor

In Angular, you will need the ability to loop over collections of items and display them. In our case, once we have some games to work with we should be able to loop over them and display them in our table. To do this, we can use *ngFor. This structural directive repeats a part of the dom tree once for each item in an iterable list such as an array. What we will do is populate the games variable in game-list.component.ts with some JSON data to represent a couple of games. In the future, we will set this up as a service to fetch data from the server.

Now, in the game-list.component.html we can make use of that *ngFor structural directive to loop over the two games.

The result in the browser is now that the two games are iterated over, and we see their data on the page.
angular ngfor example

A note about for of vs for in

In the example above, we see that *ngFor made use of the for of looping construct. This is because the for of loop is able to iterate over any iterable type like an array. It produces the value stored in each index, not the index itself. for of on the other hand produces the index value such as 0, 1, 2, etc… You can think of for in as an index specific iterator.

In Summary

  • Templates
    • Inline
      • Best used with shorter markup length
      • Makes use of the template property
      • Can use double or single quotes for single line templates
      • Uses back ticks for multi line templates
      • No intellisense or auto code formatting
    • Linked Templates
      • Best once html markup becomes longer
      • Uses the templateUrl property
      • Defines a path to the html template file
  • Components As Directives
    • Use the element as a directive in the component such as <game-list></game-list>
    • Declare the component in the associated Module using the declarations array
  • Interpolation
    • Is a one way data binding
    • Data travels from class property to element property
    • Defined using {{ }} curly braces
  • Structural Directives
    • prefixed with an asterisk * character
    • Assigned to a quoted string expression
    • *ngIf used to add or remove an element and its children from the Dom
    • Based on expression which evaluates to true or false
    • *ngFor is used to repeat an element and its children in the dom.
    • Use let as the type of local variable in the loop
    • Use “of” not “in” when creating the expression