Generate an App page

Learn how to generate an Angular 13 application with it's command line interface (CLI).

How to Use This Guide

This guide will walk you through building an application in Angular 13. Each page of the guide is based on building a new feature, and may have multiple "problems" to solve. Each problem will be explained and include requirements and any set-up steps needed. Most problems will also include unit tests to update to verify the solution has been implemented correctly. The ✏️ icon will be used to indicate when commands need to be run or when files need to be updated. If you have any issues or suggestions as you move through this training, we'd love you to submit a GitHub issue for it! πŸ’–

Overview

In this part, we will:

  • Explore tools that aid Angular Development
  • Install Angular's CLI
  • Generate a new app
  • Look at the files generated by the cli
  • Learn to serve our app

Problem

We want to create a new Angular application and update it to say Place My Order App: Coming Soon! in an <h1> element.

What You Need to Know

To complete this exercise, you are going to want:

  • Select a code editor / IDE
  • To install Angular's CLI
  • Use the CLI to generate a new app
  • Understand the files generated
  • Serve the app

Selecting a code editor

If you're looking for a code editor (aka IDE) to improve your Angular development - VS Code is widely used by the community but other editors like Webstorm are fine as well. Plugins can go a long way in aiding the development process.

Visual Studio Code

VS Code is Microsoft's modern take on an IDE for app development (P.S. TypeScript is a Microsoft Open Source project). VS Code has built in TypeScript support for syntax highlighting, IntelliSense code completion, and linting.

Visual Studio Code screenshot

Helpful Plugins:

Webstorm

Webstorm is a platform by JetBrains that is loved for its great code refactoring assistance and version control integration, but it does require a paid subscription.

Webstorm screenshot

Helpful Plugins:

Installing the CLI

Angular has a command line interface or CLI that does a lot of the initial legwork in setting up a minimal app, as well as letting you easily create and include new components on the fly.

We'll start by globally installing the Angular CLI.

✏️ Run the following:

npm install -g @angular/cli@13

Generating a new app

We're going to build a restaurant menu and ordering application. The final result will look like this:

Place My Order App screenshot

(reminder: You can see a DoneJS implementation of this application at www.place-my-order.com)

✏️ To create a new Angular Workspace, run the 'ng new' command:

ng new place-my-order --prefix pmo
cd place-my-order

This will create a new Angular Workspace, generate an app module, needed config files, and test suite for your new Angular project. You'll be asked a series of set-up questions:

  1. Would you like to add Angular routing? (yes)
  2. Which stylesheet format would you like to use? (Less)

Note that we used the prefix property to set our own default prefix. Angular's default is "app", but a good naming convention is to use a short prefix related to your company or application name to easily differentiate from 3rd party utilities.

<!-- this looks like it's one of our own app components -->
<pmo-header></pmo-header>

<!-- safe to assume this a 3rd party -->
<tabset>
  <tab heading="Basic title" id="tab1">Basic content</tab>
  <tab heading="Basic Title 1">Basic content 1</tab>
  <tab heading="Basic Title 2">Basic content 2</tab>
</tabset>

There are several more helpful properties that customize how a project is set up.

Looking at Our Generated Workspace

Let's walk through some of the files that were generated.

β”œβ”€β”€ node_modules/
β”œβ”€β”€ src/
|   β”œβ”€β”€ app/
|   |   β”œβ”€β”€ app-routing.module.ts
|   |   β”œβ”€β”€ app.component.html
|   |   β”œβ”€β”€ app.component.less
|   |   β”œβ”€β”€ app.component.spec.ts
|   |   β”œβ”€β”€ app.component.ts
|   |   β”œβ”€β”€ app.module.ts
|   β”œβ”€β”€ assets/
|   β”œβ”€β”€ environments/
|   |   β”œβ”€β”€ environment.prod.ts
|   |   β”œβ”€β”€ environment.ts
|   β”œβ”€β”€ index.html
|   β”œβ”€β”€ main.ts
|   β”œβ”€β”€ polyfills.ts
|   β”œβ”€β”€ styles.less
|   β”œβ”€β”€ test.ts
β”œβ”€β”€ .browserslistrc
β”œβ”€β”€ angular.json
β”œβ”€β”€ karma.conf.json
β”œβ”€β”€ package-lock.json
β”œβ”€β”€ package.json
β”œβ”€β”€ README.md
β”œβ”€β”€ tsconfig.app.json
β”œβ”€β”€ tsconfig.json
β”œβ”€β”€ tsconfig.spec.json

angular.json

This file is the config schema for an Angular Workspace. By default Angular configures Webpack for it's build process, and uses the angular.json file for the build information.

(Note, prior to Angular v6, this file was .angular-cli.json. When migrating versions, having the wrong workspace config file name is a cause for problems.)

tsconfig.json

This file contains our TypeScript compiling options. Starting from Angular 12, "strict mode" is set to true by default. Angular's strict mode enforces the TypeScript strict flag and a few additional TypeScript rules: forceConsistentCasingInFileNames, noImplicitReturns, noFallthroughCasesInSwitch. Additionally this mode turns on Angular-specific compiler flags strictTemplates, strictInjectionParameters and strictInputAccessModifiers. This Template type checking was made available with Angular Ivy and will throw compiler errors for incorrect typings inside templates.

/* To learn more about this file see: https://angular.io/config/tsconfig. */
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "sourceMap": true,
    "declaration": false,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "target": "es2017",
    "module": "es2020",
    "lib": [
      "es2020",
      "dom"
    ]
  },
  "angularCompilerOptions": {
    "enableI18nLegacyMessageIdFormat": false,
    "strictInjectionParameters": true,
    "strictInputAccessModifiers": true,
    "strictTemplates": true
  }
}

src/main.ts

This is the entry point of our application, it compiles and bootstraps our app.

src/index.html

This should feel familiar - our main index page.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>PlaceMyOrder</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>
  <!-- our entry component -->
  <pmo-root></pmo-root>
</body>
</html>

src/app/app.module.ts

This file is the root module for our app. Every Angular app has at least one module that determines how to compile and launch an app. It uses the @NgModule decorator with four properties:

  • declarations [array]: where we include components, directives, and pipes that will be used by this module.
  • imports [array]: where we include any other modules our app needs to use. This may include 3rd party modules like bootstrap datepickers, or modules we've created.
  • providers [array]: where we include services that we want used at the module level
  • bootstrap [array]: where we include the root AppModule - this is the main Application view that hosts all of our other app views.

Further reading: Dependency Injection in Angular

src/app/app.component.ts

This is our root component, you saw it called in our index.html file as <pmo-root></pmo-root>

Serving An Application

✏️ Serve the app with:

npm run start

The start script command value is ng serve which starts a development server on port 4200 by default using webpack-dev-server, and compiles a development version of the app. Any TypeScript errors will be caught by the compiler here, and once ready we can view our app at localhost:4200. ng serve also has live-reload functionality, meaning the browser will automatically reload as changes are saved and compiled.

Running Tests

When we use the CLI to create modules, components, services, etc, it will create spec files for us.

✏️ Run tests in a new command line with:

npm run test

How to Verify Your Solution is Correct

The change we needed to make for our tests to pass is on the highlighted line 37.

We also included schemas metadata for our module. NO_ERRORS_SCHEMA will keep the compiler from throwing errors when unknown components are included in the tested components. In unit tests we often only want to test the very small piece of code we're working on and don't care about deeply nested components unless we're testing the props in a parent/child component relationship. For our purposes in this training, it's safe to use here.

✏️ Update src/app.component.spec.ts:

import { NO_ERRORS_SCHEMA } from '@angular/core';
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';

describe('AppComponent', () => {
  beforeEach(async () => {
    await TestBed.configureTestingModule({
      imports: [
        RouterTestingModule
      ],
      declarations: [
        AppComponent
      ],
      schemas: [
        NO_ERRORS_SCHEMA
      ]
    }).compileComponents();
  });

  it('should create the app', () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app).toBeTruthy();
  });

  it(`should have as title 'place-my-order'`, () => {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.componentInstance;
    expect(app.title).toEqual('place-my-order');
  });

  it('should render title in a h1 tag', () => {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.nativeElement as HTMLElement;
    expect(compiled.querySelector('h1')?.textContent).toContain('Place My Order App: Coming Soon!');
  });
});

Solution

Click to see the solution Let's change the markup to look like the home page of our place my order app.

✏️ Update src/app/app.component.html to:

<h1>Place My Order App: Coming Soon!</h1>
<router-outlet></router-outlet>

When you save your changes, you should see the new h1 tag in your browser at localhost:4200.