Your First Angular 2, ASP.NET Core Project in Visual Studio Code – Part 4

Angular2, ASP.NET Core, Visual Studio Code, Part 4

Derived from photo by Markus Spiske / raumrot.com, CC-BY

This is part four in a series of posts teaching you how to create your first Angular 2 application with ASP.NET Core in Visual Studio Code. Here is the list of posts:

In this post, you write a 'Hello World' style Angular 2 application. You are introduced to components, NgModules, and template syntax. The walkthrough discusses how to bootstrap an Angular 2 application in the browser and along the way you learn how to better manage your TypeScript files in Visual Studio Code.

This post scratches the very surface of what Angular 2 offers. It's included in the series for completeness and to offer perspective regarding the framework's fundamental building blocks. It is not intended to replace the excellent documentation that the Angular team has produced. So when you get the chance, please take some time and go through the Angular 2 Tour of Heroes Tutorial to learn about the wider breadth of features available in the framework.

Note: If you have been following along with the series prior to this post being published, there is an update to the Part 3 Angular 2 configuration. Please ensure you have the @types/node package installed in your devDependencies. This typings library contains definitions for the module.id API used in this part of the walkthrough.

If you would like to jump straight to the code, it's all on GitHub.

Define the Root Tag

First, add a custom tag to your index.html file. Angular uses the custom tag as an identifier for where in the document to render the application. Any content between the opening and closing tags is replaced during the bootstrap process, so this is a convenient place to add a loading message or indicator. Within the body of your index.html page, add the custom my-app element:

<body>
    <my-app>Loading...</my-app>
</body>

Your First Component

It's time to create your first Angular 2 component. An Angular 2 component is essentially a JavaScript class adorned with the @Component decorator in which you define a template. The class encapsulates the behavior of the component and the template encapsulates the view. Angular does the work to wire the view to the behavior for you.

Components are the building blocks of your application. At the root of your application, is a component containing other components, composed together to form a user interface. This composition is sometimes called a component tree where the root component contains all of the other components in your application and leaf components represent the re-usable widgets of your application with which the user interacts.

Component tree

Create a file within your application's app directory called app.component.ts. Go head and add this component code:

import { Component } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'my-app',    
    template: 'Hello, Angular 2 World!',
})
export class AppComponent { }

The @Component syntax is a decorator. This code adorns the AppComponent class and adds metadata information about the class. In this case, it denotes that this class is an Angular 2 component.

The import statement obtains the Component decorater from the @angular/core library. This import statement is an example of node module resolution which you setup in part 3 of this series. The Component decorator sets three properties, moduleId, selector, and template.

The moduleId property, when used, is generally set in this fashion. By setting it to module.id, you are supplying the current ECMAScript 2015 module's URL to Angular. This helps the framework load external templates and styles from the same relative location (URL) as the component's scripts. In this example, the component has no external templates or styles and thus setting moduleId is not required. However you may find it's easier to always set moduleId than to keep track of when you need it and when you don't.

Angular uses the selector property as a CSS selector to query a template finding all the elements that should be initialized as this component. For instance, when you use this component in a view, you define it as <my-app></my-app>. This selector is a tag selector, because it targets elements by tag name. But you can use other CSS selector types. If you prefer to define your components in markup by class (.my-app) or by attribute ([my-app]) simply change the selector accordingly.

The template property is the view or markup rendered for the component. In a moment, you will explore the template syntax more. It's important to note that there are two template-related properties available on the Component decorator: template and templateUrl. The templateUrl property points to a separate file containing the markup. For any template more than a couple lines, creating a separate file and using templateUrl is generally easier. You'll find in Visual Studio Code (and probably many other editors) that having the extra HTML syntax highlighting and auto-complete when writing in a dedicated .html file is more productive.

Finally, the Component decorator annotates the component class definition. The Angular 2 Style Guide recommends suffixing class names with the Angular object type which is why this class is named AppComponent but ultimately you have the freedom to decide which naming convention to use. Notice the class is exported using the export keyword so that it can be consumed in other ECMAScript modules as you will soon see. Finally, this component is very simple with no behavior which is why the class definition doesn't have much code yet.

Your First Angular Module

Angular 2 brings forward the concept of Angular modules from Angular 1.x although in quite a different form. In Angular 2, Angular modules are defined with the NgModule decorator. To distinguish from ECMAScript 2015 (ES2015) modules, this post will refer to them as NgModules.

First, what's the difference between an NgModule and an ES2015 module? You can think of ES2015 modules as encapsulated, reusable units of code whereas NgModules are encapsulated, reusable units of the application. NgModules are composed of ES2015 modules making them a sort of higher-order unit. Again coming from the Angular 1.x world, NgModules are very similar conceptually to angular.module. If you are coming from a C#/.NET background, you can almost think of NgModules as namespaces or assemblies.

Angular requires you to have at least one NgModule in your application. For small applications this may be preferable, but as your code base grows adding additional NgModules may help you reason about the application.

For this example, create one NgModule to house and bootstrap your application. In the app directory, create the app.module.ts file and add this code:

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

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

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

Notice that all the configuration occurs in the NgModule decorator. The bootstrap property is only necessary in this root NgModule. It instructs Angular to examine the existing DOM (parsed from index.html in this case), identifying the elements to replace with the components defined in bootstrap.

The imports property defines any NgModules that are consumed by this NgModule. Being this root NgModule is running in a browser, you must import the BrowserModule. The other NgModules in your application do not need to import that BrowserModule, only the root NgModule.

Finally, you declare all of the Components and Directives that belong to this NgModule in declarations. There are several other important properties with the NgModule decorator so refer to the documentation for more information.

Bootstrap the Application

Angular 2 provides multiple ways to bootstrap your application depending on where it is running (server versus browser) and whether it has been compiled ahead of time (AOT) or not. For this example, use just-in-time (JIT) compilation in the browser with platformBrowserDynamic to bootstrap the AppModule. In your main.ts file, replace the contents with this:

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

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

platformBrowserDynamic().bootstrapModule(AppModule);

Save all of your files and start your application. From the terminal (Ctrl+`), type npm start to compile the TypeScript and start your ASP.NET Core application. Then view the application in the browser at http://localhost:5000. You see the message 'Hello, Angular 2 World!'

Hello, Angular 2 World!

Hide Generated TypeScript Files

At this point, you have three TypeScript files in your app directory and also six additional .js and .js.map files generated from the TypeScript build.

TypeScript generated files

Having three of each file name in the explorer pane can make it difficult to find the actual file you need. Furthermore, you don't really need to see the JavaScript and source map files during development. To address this, Visual Studio Code has settings to hide these files in the explorer pane.

There are two options when changing Visual Studio Code settings. The editor allows you to configure settings for your user profile on the development machine. In this way, all of your projects pick up the same settings on that machine but unless you manually back it up, those settings could be lost.

You also have the option to configure settings for your workspace which are easy to save in source control and restored on whichever machine you use. The downside is that they are only applied to that particular project. For this exercise, you are configuring workspace settings.

In the File menu, select Preferences, then click Workspace Settings. This creates a .vscode directory in your application root containing a file named settings.json.

File Menu, Workspace Settings

This file contains a set of matching curly braces. Within those curly braces, begin typing "files.exclude" but press TAB before the closing quote symbol. When you press TAB to trigger autocomplete, the default excluded files and directories are populated.

settings.json auto-complete

To that list of globs, add one to hide the source map files and one to hide the generated JavaScript files. When you are done the configuration looks like this:

{
    "files.exclude": {
        "**/.git": true,
        "**/.svn": true,
        "**/.hg": true,
        "**/.DS_Store": true,
        "**/*.js.map": true,
        "**/*.js": { "when" : "$(basename).ts" }
    }
}

When you save the file, you see that now only the TypeScript files are visible in the explorer pane.

No TypeScript Generated Files

Template Syntax

To wrap up this Angular example, you explore the Angular 2 template syntax. Open up the app.component.ts file to make changes to this component.

First, add a property to the component class called food and set it to your favorite food. Then, replace the template property with a basic template. Your component should look like the following:

import { Component } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'my-app',    
    template: `
        <input type="text" [value]="food" />
        <p>Sriracha sauce is great with {{ food }}</p>
    `,
})
export class AppComponent { 
    food = 'kielbasa';
}

Go head and refresh your browser to see the changes. Also, ensure the request is not pulling from the browser cache.

Template Syntax Example

The first thing to point out is that the template is defined using the ES2015 template literal string syntax. This syntax uses the back-tick character (grave accent) and supports multi-line string values. TypeScript outputs ES5-compatible strings at compile-time.

Also, you see two examples of Angular-specific template syntax. First, the value attribute of the input is surrounded by square brackets []. This is called a property binding because it binds to the property of an element. In this case, the input's value property is set to the resulting evaluation of the component's food property. This syntax replaces the need for a specialized Angular directive. You are instead targeting the element's native properties, setting the bindings using an abbreviated syntax.

On the second line of the template, you see the double curly braces used {{ }} to bind to the same component property. This is the interpolation syntax. When changes to the component are made, the expression inside the curly braces is evaluated and the resulting value is coerced to a string and inserted into the DOM. This syntax is similar to Angular 1.x, although some of the rules around how expressions are evaluated have changed.

Now, edit the value in the text input. You see that it doesn't update the value in the paragraph. The binding only operates from the component to the view, not the other way around.

value doesn't change

To update the value, you wire-up one of the element's events with a method on your component. Instead of wrapping the event name in square brackets [], you wrap it in parentheses () For this example use the input event and create a method on the component class called foodInput to handle the event. This is called an event binding. Your component code should now look like this:

import { Component } from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'my-app',    
    template: `
        <input type="text" [value]="food" (input)="foodInput($event)"/>
        <p>Sriracha sauce is great with {{ food }}</p>
    `,
})
export class AppComponent { 
    food = 'kielbasa';

    foodInput(event: Event) {
        const target = event.target as HTMLInputElement;
        this.food = target.value;
    }
}

Notice in the template, the $event argument is passed to the foodInput method. This represents the argument that you would receive if you had handled the event in the DOM. Furthermore, look at the typings applied to the method. Both the Event and HTMLInputElement types help you use the API in the method. Ultimately, you take the new value from the event arguments and set it to the food property on the component which in turn updates the binding in the template.

value does change

In the past, you may have used two-way binding in Angular 1.x. Two-way binding is still around but the Angular framework is designed to support uni-directional (one-way) data patterns more easily out of the box. Read more about the template syntax here.

In Summary

You have now built an Angular 2 application sitting on top of ASP.NET Core from scratch. In this post, you learned how to bootstrap your application and learned about some of the fundamental building blocks of Angular 2 including components and NgModules. You also learned how to customize the settings in Visual Studio Code to hide files generated by TypeScript.

In the next post, you smooth out some of the rough edges with the development experience. Wouldn't it be great if your browser automatically updated after every code change? That's what part 5 covers so stay tuned.

How is your Angular 2 development going? If you used Angular 1.x, do you find that the frameworks are concept compatible? In what ways? Let everyone know in the comments.

3 thoughts on “Your First Angular 2, ASP.NET Core Project in Visual Studio Code – Part 4”

    1. Hi Ghennady, just did a sanity check of the master branch and couldn’t reproduce. Take a look at part 1 where it discusses the prerequisite installs. Then you can run it with `npm install` followed by `npm start`. If that doesn’t work and it’s unmodified, could be a configuration difference – it would be difficult to troubleshoot that through blog comments ;-). Feel free to post a GitHub issue as well, might be a better place to discuss. Please keep me posted.

    2. I think it’s because of multiple lines in “template”, i put all “Sriracha sauce is great with {{ food }}”in one single line and it worked…

Leave a Reply

Your email address will not be published. Required fields are marked *