Barbarian Meets Codingbarbarianmeetscoding

WebDev, UX & a Pinch of Fantasy

24 minutes readangular

Getting Started with Angular Step by Step: 1 - Your First Component

Earlier this week Lisa Ryrholm and I were at the ngStockholm meetup helping people get started with Angular. We’re going to have yet another workshop next week and I thought to myself… Wouldn’t it be nice if the people coming to the workshop could have a detailed reference about each and one of the exercises in the workshop? Wouldn’t it be cool if this reference had nice explanations and step by step directions that they could use during the workshop or refer back to later on? Something in a neat tutorial format? Of course!

And voilà! Here it is! Are you interested in a step by step introduction to Angular? Then let’s get started coding!

Angular Getting Started

Why Should You Care?

The JavaScript and web world has changed a lot since AngularJS was released. Angular takes advantage of all the advances that have happened since then, embraces web standards and does away with a lot of constructs that are now native to JavaScript such as modules, classes or decorators1.

And not only that, it draws on all the teachings of tons of projects carried out by thousands of developers in AngularJS to provide a more consistent and compact developer experience. One with a reduced number of concepts to grasp and an easy-to-learn development model and syntax.

It’s also faster, provides server-side rendering out of the box, is cross-platform, supports legacy browsers, etc, etc.

Angular is the natural path forward for all the AngularJS developers out there and a great choice for those that appreciate an opinionated framework with a sensible set of defaults, focus on modularity and testability.

The Code Samples

You can download the complete code samples for this blog post from this GitHub repo. You can also check the unbelievably cool online editor Stackblitz which has awesome support for writing Angular prototypes on the web. My recommendation is that you follow the tutorial along using your own development environment, that way you get to enjoy the full Angular developer experience. But if you don’t have time or energy to set it up right now, then try Stackblitz.

Getting Started With Angular and TypeScript

The best way to get started learning Angular and TypeScript is to use the Angular CLI to bootstrap a new project.

The Angular CLI is great because it includes everything you need to start writing your Angular application right away: A front-end build pipeline to transpile your TypeScript into JavaScript that can run in the browser, lots of generators to scaffold your app, a web development server that automatically reflects your changes in the browser as you make them and much more. I call that zero-friction learning :).

So start by installing the Angular CLI using npm (you’ll need to install node.js and npm in your development machine before you can continue). In your terminal of choice type:

$ npm install -g @angular/cli

Now you are ready to use the Angular CLI to create a new project. The command that you use to access the Angular CLI is ng. To create a new app type the following:

$ ng new angular-get-started --style scss

This will create a new Angular project from scratch and set it up so that you can use Sass as CSS preprocessor.

If you go inside the angular-get-started folder that should have just been created, you’ll find a folder structure that will look more or less like this:

# app source code (and specs)
- src
  - app                 # your app source code (and specs)
  - assets              # static assets like images, etc
  - index.html          # the entry point to your app
  - styles.scss         # the global styles for your app
  - environments        # here you can define different environment configuration (prod, dev, etc)

# dependencies
- node_modules          # the source code of your app's dependencies
- package.json          # the manifest of your app that states all dependencies

# TypeScript configuration
- tsconfig.json         # TypeScript compiler configuration
- tslint.json           # TypeScript linting configuration

# Testing
- e2e                   # a folder with end to end tests
- karma.conf.js         # karma test runner configuration
- protractor.conf.js    # protractor e2e tests configuration

- .gitignore            # which files should be ignored by git
- README.md             # README with project information

You can test that everything works as it should by running the development server. Type the following command:

$  ng serve --open
# the short-hand syntax is: ng s -o

This should start the development server, open a browser and load your app. You can stop the server any time by typing CTRL-C a couple of times in the terminal. But for the time being just rejoice! You have created your first Angular application!

Index.html The Entry Point for Your App

The index.html is the entry point to your application:

  • It links to your styles and javascript files
  • It provides the HTML markup for your application with the custom <app-root> element.

If you take a sneak peak at the index.html file in your project you’ll see the following:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>AngularGetStarted</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <!-- 3. Display the application -->
  <!-- this is your application root component -->
  <app-root></app-root>
</body>
</html>

You may be wondering… Hmm… where are the styles and JavaScript files? All I can see is a custom element app-root. You’ll be happy to know that you don’t have any sight problems as the styles and JavaScript files are indeed not there… yet. The reason why that is the case is that the Angular CLI relies on Webpack to inject these files when they are needed.

Bootstrapping Your App

In AngularJS we used the ng-app directive to point Angular to the starting point of your application. In Angular we use a bootstrapper. You can find the bootstrapping logic in the src/main.ts module:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch(err => console.error(err));

In this file we import the platformBrowserDynamic object from the '@angular/platform-browser-dynamic' module and call its bootstrapModule function with the AppModule as argument.

There’s two interesting things to note here:

  • The '@angular/platform-browser-dynamic' bootstrapper hints at the fact that Angular is platform agnostic. That is, you can run it in the browser, but you can also run it on a web worker or in the server using different bootstrappers.
  • Notice how we import modules in a different way, Angular modules are imported by name, and application components are imported using relative paths.

Calling the bootstrapModule function with the AppModule as argument tells Angular that this module is the main module for your application.

Wait… But What is an Angular Module? I Thought We Were Just Using ES6 Modules in Angular!

Yes, we do use standard ES6 modules in Angular. Angular modules are just a new convenience for us developers, a higher level module to wrap ES6 modules that are all about developer ergonomics.

Angular modules and the new NgModule decorator let us declare in one place all the dependencies and components of our application without the need to do it on a per-component basis (like we used to do in earlier versions):

import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'

import { AppComponent } from './app.component'

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}

The NgModule decorator takes an object with the following information:

  • an imports array where you declare your module dependencies, for instance, browser, forms, routing or http. The BrowserModule used above contains all the dependencies necessary to run Angular on a browser.
  • a declarations array where you declare the components and directives that belong to the current module.
  • a bootstrap array that identifies the root component that Angular should use to bootstrap your application.

In this example we import an AppComponent component from the app.component.ts module and set it as the root of our application.

But What is a Component?

The component is the core building block of Angular applications. It represents a reusable piece of UI that is usually depicted by a custom html element.

A component is self-contained and is constituted:

  • a piece of html code that is known as template,
  • a class that encapsulates the data and interactions available to that template,
  • the aforementioned html element also known selector
  • and some styles that define the look of the component

The AppComponent looks like this:

import { Component } from '@angular/core'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'],
})
export class AppComponent {
  title = 'angular-get-started'
}

It has an AppComponent class that is decorated by some metadata in the form of a TypeScript decorator @Component which binds the class to its template, its styles and the app-root selector (Can you remember the <app-root> element from the index.html file?).

This metadata tells Angular that whenever you see an <app-root> html element you should render the template in templateUrl, with the styles in stylesUrls and in the context of the AppComponent class.

If we take a sneak peek at the template you’ll see the following (feel free to quickly scroll through it):

<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * The content below * * * * * * * * * * * -->
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * Delete the template below * * * * * * * * * * -->
<!-- * * * * * * * to get started with your project! * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->

<style>
/** Lots of inline CSS rules here. They define the look and feel of the get started template. */
</style>

<!-- Toolbar -->
<div class="toolbar" role="banner">
  <img
    width="40"
    alt="Angular Logo"
    src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg=="
  />
  <span>Welcome</span>
    <div class="spacer"></div>
    <a aria-label="Angular on twitter" target="_blank" rel="noopener" href="https://twitter.com/angular" title="Twitter">
      <!-- svg id="twitter-logo" -->
    </a>
</div>

<div class="content" role="main">

  <!-- Highlight Card -->
  <div class="card highlight-card card-small">
    <!-- <svg id="rocket" alt="Rocket Ship" ... -->
    <span>{{ title }} app is running!</span>
    <!-- <svg id="rocket" alt="Rocket Ship Smoke" ... -->
  </div>

  <!-- Resources -->
  <h2>Resources</h2>
  <p>Here are some links to help you get started:</p>

  <!-- more html with links to docs where you can learn Angular. -->

  <!-- Next Steps -->
  <h2>Next Steps</h2>
  <p>What do you want to do next with your app?</p>

  <!-- more html with more learning resources. -->

  <!-- Terminal: Some helpful angular cli commands. -->
  <div class="terminal" [ngSwitch]="selection.value">
      <pre *ngSwitchDefault>ng generate component xyz</pre>
      <pre *ngSwitchCase="'material'">ng add @angular/material</pre>
      <pre *ngSwitchCase="'pwa'">ng add @angular/pwa</pre>
      <pre *ngSwitchCase="'dependency'">ng add _____</pre>
      <pre *ngSwitchCase="'test'">ng test</pre>
      <pre *ngSwitchCase="'build'">ng build --prod</pre>
  </div>

  <!-- some more html -->

</div>

<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * * The content above * * * * * * * * * * * -->
<!-- * * * * * * * * * * is only a placeholder * * * * * * * * * * -->
<!-- * * * * * * * * * * and can be replaced. * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->
<!-- * * * * * * * * * * End of Placeholder * * * * * * * * * * * -->
<!-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -->

Let’s simplify this boilerplate getting started component. Remove everything and just keep a simple header with the title of our site:

<h1>
  {{ title }}
</h1>

The title bit (which we call interpolation syntax) tells Angular to display the content of the component title variable when rendering the component. Indeed, if you run ng serve you can see how the browser renders the text angular-get-started inside an h1 element.

If you take a look back at the AppComponent definition and at your project structure you’ll realize that the Angular CLI follows a convention when creating components:

  • All files for a given component are placed within the same folder named like the component itself (in this case app)
  • These files are named with app.component and have different extensions based on their function:

    • app.component.ts for the component itself
    • app.component.html for the template
    • app.component.scss for the styles

Now let’s do a quick test to see how we can bind the AppComponent class members to the template. Let’s change the title property value from angular-get-started to Star Wars PPlz!!!!!. If you now save the file, your browser should automagically refresh itself and you should be able to see the Star Wars PPlz!!! as the title of your app (If you closed your browser just open it again and if you stopped the development server then remember to run ng serve --open to start it again and see your changes).

Your First Component, Listing Star Wars People Of Note!

Lisa and I were discussing for a while which super duper cool service we would use for our workshop… Spotify, SoundCloud, instagram… And all of the sudden we found this free and open Star Wars web api. So that’s what we’re going to be building, a gateway into the Star Wars universe. Starting with its peoples of note: heroes, villains and everyone in between!

The first thing that we are going to do is not going to require apis or services, not yet. We are going to create our first component to display a list of Star Wars people and we will start faking out that data. Learning is easier when you take it one little step at a time.

It is good practice to start building an application by defining the domain model of our problem space, in this case a Person. We’ll take advantage of TypeScript’s interface (although we could’ve used a class as well) and create a Person within the person.ts file. But we won’t create it by hand, we will use the Angular CLI! Angular CLI to the rescue!

The Angular CLI has something that we call generators that lets you generate (or scaffold) parts of your application for you. For example, you can use the following command to create an interface:

$ ng generate interface person
# or in short-hand:
# ng g i person

The result of running this command is a person.ts file in your app folder:

export interface Person {}

Now let’s add some properties that are representative of a person:

export interface Person {
  name: string
  weight: number
  height: number
}

Now that we have defined the core object of our domain model let’s create our very first component: the PeopleListComponent. Again we take advantage of the Angular CLI and type the following:

$ ng generate component --inline-template people-list
# or in short-hand:
# ng g c -t people-list

This will generate a new folder people-list and will place a TypeScript and a style file within that folder.

Since we have selected the --inline-template option, instead of using an external template file (something like people-list.component.html) the component will use the template property inside the @Component decorator to define an inline template. That is, the html template for this component will be right there with the component itself. Components with inline templates are really nice because it is very easy to see how the template relates to the logic that controls that template.

Your new component looks like this:

import { Component, OnInit } from '@angular/core'

@Component({
  selector: 'app-people-list',
  template: `
    <p>
      people-list Works!
    </p>
  `,
  styleUrls: ['./people-list.component.scss'],
})
export class PeopleListComponent implements OnInit {
  // you can ignore these for the time being :)
  constructor() {}
  ngOnInit() {}
}

Ok, now we’ve got a component that we can render using the <app-people-list> element. Looking at the component, you can appreciate how the Angular CLI creates a dummy template so you can test that the component works right away. But let’s wait a bit. We still need to do some changes before we can display a list of Star Wars celebrities.

The next thing that we’ll do is to expose a people property with an array of Person with the mighty Luke, Darth Vader and Solo.

import { Component, OnInit } from '@angular/core';
import {Person} from '../person';

@Component({
  selector: 'app-people-list',
  template: `
    <p>
      people-list works!
    </p>
  `,
  styleUrls: ['./people-list.component.scss']
})
export class PeopleListComponent implements OnInit {
  people: Person[] = [
    { name: 'Luke Skywalker', height: 177, weight: 70 },
    { name: 'Darth Vader', height: 200, weight: 100 },
    { name: 'Han Solo', height: 185, weight: 85 },
  ]

  constructor() { }
  ngOnInit(): void {}

}

And now we’ll update its template so that we can represent a list of star wars people. Just like ng-repeat in AngularJS, Angular provides a repeater directive that let’s us repeat a part of a template: *ngFor:

  <!-- this is the new syntax for ng-repeat -->
  <ul>
    <li *ngFor="let person of people">
      {{person.name}}
    </li>
  </ul>

The * before the ngFor denotes the fact that *ngFor is what is called a structural directive, a directive that is going to affect the DOM in some way adding or removing elements to it. Soon you’ll notice how Angular uses a lot of these cues in their syntax to convey a specific meaning and help you learn and understand what the different directives and parts of the framework do.

The let person creates a local template variable that contains each item within the people array and is bound to each li element.

Putting everything together we get:

import { Component, OnInit } from '@angular/core';
import { Person } from '../person';

@Component({
  selector: 'app-people-list',
  template: `
    <ul>
      <li *ngFor="let person of people">
        {{ person.name }}
      </li>
    </ul>
  `,
  styleUrls: ['./people-list.component.scss'],
})
export class PeopleListComponent implements OnInit {
  people: Person[] = [
    { name: 'Luke Skywalker', height: 177, weight: 70 },
    { name: 'Darth Vader', height: 200, weight: 100 },
    { name: 'Han Solo', height: 185, weight: 85 },
  ];

  constructor() {}
  ngOnInit(): void {}
}

Now we can update our AppComponent to display the list of StarWars people. We only need to update the app.component.html template:

<h1>{{title}}</h1>
<app-people-list></app-people-list>

And voilà!!!!! It works! (again check the browser for an update or run ng serve -o).

Once thing that is interesting to mention is that if you had followed the previous steps but you had created the new component with your bare hands it would not have worked. Why is that? That’s because the Angular CLI does a lot of things for you in the background. For instance, when we created the component before, the CLI did not only create the component itself but it also wired it up so we could use it in our application.

Indeed, in order to be able to use a component within another component you need to make your application aware of it. You can do that in the app.module.ts file, that is, in your Angular module. If you take a look at this file you’ll discover the following:

import { AppComponent } from './app.component'
// who did this?
import { PeopleListComponent } from './people-list/people-list.component'

@NgModule({
  declarations: [
    AppComponent,
    PeopleListComponent, // and this??
  ],
  // etc...
})
export class AppModule {}

Exactly! The Angular CLI has wired it up for you and saves you the need to remember to do it yourself. Magnificent! Thor bless the Angular CLI!

Concluding

Good job! You’ve started your path to learning Angular! Yey! We touched a ton of stuff in this blog post, Angular, TypeScript, the Angular CLI, modules, Webpack, bootstrapping, components, decorators, classes and template strings. Wow! Hope you’ve enjoyed the tutorial!

Up next! Refactoring to services!


  1. Decorators are a proposal level 1 still but they are available with Babel and within TypeScript.


Jaime González García

Written by Jaime González García , Dad, Husband, Front-end software engineer, UX designer, amateur pixel artist, tinkerer and master of the arcane arts. You should follow him on Twitter where he shares useful stuff! (and is funny too).Jaime González García