In this article by Shravan Kumar Kasagoni, the author of the book Angular UI Development, we will learn how to use new features of Angular framework to build web components. After going through this article you will understand the following:
- What are web components
- How to setup the project for Angular application development
- Data binding in Angular
(For more resources related to this topic, see here.)
Web components
In today’s web world if we need to use any of the UI components provided by libraries like jQuery UI, YUI library and so on. We write lot of imperative JavaScript code, we can’t use them simply in declarative fashion like HTML markup.
There are fundamental problems with the approach. There is no way to define custom HTML elements to use them in declarative fashion. The JavaScript, CSS code inside UI components can accidentally modify other parts of our web pages, our code can also accidentally modify UI components, which is unintended. There is no standard way to encapsulate code inside these UI components.
Web Components provides solution to all these problems. Web Components are set of specifications for building reusable UI components.
Web Components specifications is comprised of four parts:
- Templates: Allows us to declare fragments of HTML that can be cloned and inserted in the document by script
- Shadow DOM: Solves DOM tree encapsulation problem
- Custom elements: Allows us to define custom HTML tags for UI components
- HTML imports: Allows to us add UI components to web page using import statement
More information on web components can be found at: https://www.w3.org/TR/components-intro/.
Component are the fundament building blocks of any Angular application. Components in Angular are built on top of the web components specification. Web components specification is still under development and might change in future, not all browsers supports it. But Angular provides very high abstraction so that we don’t need to deal with multiple technologies in web components. Even if specification changes Angular can take care of internally, it provides much simpler API to write web components.
Getting started with Angular
We know Angular is completely re-written from scratch, so everything is new in Angular. In this article we will discuss few important features like data binding, new templating syntax and built-in directives. We are going use more practical approach to learn these new features. In the next section we are going to look at the partially implemented Angular application. We will incrementally use Angular new features to implement this application. Follow the instruction specified in next section to setup sample application.
Project Setup
Here is a sample application with required Angular configuration and some sample code.
Application Structure
Create directory structure, files as mentioned below and copy the code into files from next section.
Source Code
package.json
We are going to use npm as our package manager to download libraries and packages required for our application development. Copy the following code to package.json file.
{
"name": "display-data",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"tsc": "tsc",
"tsc:w": "tsc -w",
"lite": "lite-server",
"start": "concurrent "npm run tsc:w" "npm run lite" "
},
"author": "Shravan",
"license": "ISC",
"dependencies": {
"angular2": "^2.0.0-beta.1",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.13",
"reflect-metadata": "^0.1.2",
"rxjs": "^5.0.0-beta.0",
"systemjs": "^0.19.14",
"zone.js": "^0.5.10"
},
"devDependencies": {
"concurrently": "^1.0.0",
"lite-server": "^1.3.2",
"typescript": "^1.7.5"
}
}
The package.json file holds metadata for npm, in the preceding code snippet there are two important sections:
- dependencies: It holds all the packages required for an application to run
- devDependencies: It holds all the packages required only for development
Once we add the preceding package.json file to our project we should run the following command at the root of our application.
$ npm install
The preceding command will create node_modules directory in the root of project and downloads all the packages mentioned in dependencies, devDependencies sections into node_modules directory.
There is one more important section, that is scripts. We will discuss about scripts section, when we are ready to run our application.
tsconfig.json
Copy the below code to tsconfig.json file.
{
"compilerOptions": {
"target": "es5",
"module": "system",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules"
]
}
We are going to use TypeScript for developing our Angular applications. The tsconfig.json file is the configuration file for TypeScript compiler. Options specified in this file are used while transpiling our code into JavaScript. This is totally optional, if we don’t use it TypeScript compiler use are all default flags during compilation. But this is the best way to pass the flags to TypeScript compiler.
Following is the expiation for each flag specified in tsconfig.json:
- target: Specifies ECMAScript target version: ‘ES3’ (default), ‘ES5’, or ‘ES6’
- module: Specifies module code generation: ‘commonjs’, ‘amd’, ‘system’, ‘umd’ or ‘es6’
- moduleResolution: Specifies module resolution strategy: ‘node’ (Node.js) or ‘classic’ (TypeScript pre-1.6)
- sourceMap: If true generates corresponding ‘.map’ file for .js file
- emitDecoratorMetadata: If true enables the output JavaScript to create the metadata for the decorators
- experimentalDecorators: If true enables experimental support for ES7 decorators
- removeComments: If true, removes comments from output JavaScript files
- noImplicitAny: If true raise error if we use ‘any’ type on expressions and declarations
- exclude: If specified, the compiler will not compile the TypeScript files in the containing directory and subdirectories
index.html
Copy the following code to index.html file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Top 10 Fastest Cars in the World</title>
<link rel="stylesheet" href="app/site.css">
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/angular2/bundles/angular2.dev.js"></script>
<script>
System.config({
transpiler: 'typescript',
typescriptOptions: {emitDecoratorMetadata: true},
map: {typescript: 'node_modules/typescript/lib/typescript.js'},
packages: {
'app' : {
defaultExtension: 'ts'
}
}
});
System.import('app/boot').then(null, console.error.bind(console));
</script>
</head>
<body>
<cars-list>Loading...</cars-list>
</body>
</html>
This is startup page of our application, it contains required angular scripts, SystemJS configuration for module loading. Body tag contains <cars-list> tag which renders the root component of our application. However, I want to point out one specific statement:
The System.import(‘app/boot’) statement will import boot module from app package. Physically it loading boot.js file under app folder.
car.ts
Copy the following code to car.ts file.
export interface Car {
make: string;
model: string;
speed: number;
}
We are defining a car model using TypeScript interface, we are going to use this car model object in our components.
app.component.ts
Copy the following code to app.component.ts file.
import {Component} from 'angular2/core';
@Component({
selector: 'cars-list',
template: ''
})
export class AppComponent {
public heading = "Top 10 Fastest Cars in the World";
}
Important points about AppComponent class:
- The AppComponent class is our application root component, it has one public property named ‘heading’
- The AppComponent class is decorated with @Component() function with selector, template properties in its configuration object
- The @Component() function is imported using ES2015 module import syntax from ‘angular2/core’ module in Angular library
- We are also exporting the AppComponent class as module using export keyword
- Other modules in application can also import the AppComponent class using module name (app.component – file name without extension) using ES2015 module import syntax
boot.ts
Copy the following code to boot.ts file.
import {bootstrap} from 'angular2/platform/browser'
import {AppComponent} from './app.component';
bootstrap(AppComponent);
In this file we are importing bootstrap() function from ‘angular2/platform/browser’ module and the AppComponent class from ‘app.component’ module. Next we are invoking bootstrap() function with the AppComponent class as parameter, this will instantiate an Angular application with the AppComponent as root component.
site.css
Copy the following code to site.css file.
* {
font-family: 'Segoe UI Light', 'Helvetica Neue', 'Segoe UI', 'Segoe';
color: rgb(51, 51, 51);
}
This file contains some basic styles for our application.
Working with data in Angular
In any typical web application, we need to display data on a HTML page and read the data from input controls on a HTML page. In Angular everything is a component, HTML page is represented as template and it is always associated with a component class. Application data lives on component’s class properties.
Either push values to template or pull values from template, to do this we need to bind the properties of component class to the controls on the template. This mechanism is known as data binding.
Data binding in angular allows us to use simple syntax to push or pull data. When we bind the properties of component class to the controls on the template, if the data on the properties changes, Angular will automatically update the template to display the latest data and vice versa. We can also control the direction of data flow (from component to template, from template to component).
Displaying Data using Interpolation
If we go back to our AppComponent class in sample application, we have heading property. We need to display this heading property on the template.
Here is the revised AppComponent class: app/app.component.ts
import {Component} from 'angular2/core';
@Component({
selector: 'cars-list',
template: '<h1>{{heading}}</h1>'
})
export class AppComponent {
public heading = "Top 10 Fastest Cars in the World";
}
In @Component() function we updated template property with expression {{heading}} surrounded by h1 tag. The double curly braces are the interpolation syntax in Angular. Any property on the class we need to display on the template, use the property name surrounded by double curly braces. Angular will automatically render the value of property on the browser screen.
Let’s run our application, go to command line and navigate to the root of the application structure, then run the following command.
$ npm start
The preceding start command is part of scripts section in package.json file. It is invoking two other commands npm run tsc:w, npm run lite.
- npm run tsc:w: This command is performing the following actions:
- It is invoking TypeScript compiler in watch mode
- TypeScript compiler will compile all our TypeScript files to JavaScript using configuration mentioned in tsconfig.json
- TypeScript compiler will not exit after the compilation is over, it will wait for changes in TypeScript files
- Whenever we modify any TypeScript file, on the fly compiler will compile them to JavaScript
- npm run lite: This command will start a lite weight Node.js web server and launches our application in browser
Now we can continue to make the changes in our application. Changes are detected and browser will refresh automatically with updates.
Output in the browser:
Let’s further extend this simple application, we are going to bind the heading property to a textbox, here is revised template:
template: `
<h1>{{heading}}</h1>
<input type="text" value="{{heading}}"/>
`
If we notice the template it is a multiline string and it is surrounded by ` (backquote/ backtick) symbols instead of single or double quotes.
The backtick (“) symbols are new multi-line string syntax in ECMAScript 2015.
We don’t need start our application again, as mentioned earlier it will automatically refresh the browser with updated output until we stop ‘npm start’ command is at command line.
Output in the browser:
Now textbox also displaying the same value in heading property. Let’s change the value in textbox by typing something, then hit the tab button. We don’t see any changes happening on the browser.
But as mentioned earlier in data binding whenever we change the value of any control on the template, which is bind to a property of component class it should update the property value. Then any other controls bind to same property should also display the updated value. In browser h1 tag should also display the same text whatever we type in textbox, but it won’t happen.
Summary
We started this article by covering introduction to web components. Next we discussed a sample application which is the foundation for this article. Then we discussed how to write components using new features in Angular to like data binding and new templating syntaxes using lot of examples.
By the end of this article, you should have good understanding of Angular new concepts and should be able to write basic components.
Resources for Article:
Further resources on this subject:
- Get Familiar with Angular [article]
- Gearing Up for Bootstrap 4 [article]
- Angular’s component architecture [article]