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:
(For more resources related to this topic, see here.)
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:
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.
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.
Here is a sample application with required Angular configuration and some sample code.
Create directory structure, files as mentioned below and copy the code into files from next section.
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:
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.
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:
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.
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.
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:
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.
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.
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).
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.
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.
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.
Further resources on this subject: