Consume Web API OData with ODataAngularResources

One month ago, I wrote this post about the odata services and how we can consume those with the $http factory of Angularjs.

This approach is not wrong but is not smart at all, because we have to write every query for any call that the application needs to do, and is not flexible.

What we could do is write our custom library that deal with the odata url format and it expose some fluent methods that the components of the application can call; in this way we have a layer between the angular services and the odata controller and the code should be more readable.

Anyway, write a library like that is not very easy and require a lot of amount of time.

The solution of these problems is a library already implemented that we can use directly in our angular application, that is ODataAngularResources.

This is a lightweight library that allow writing the OData queries with fluent methods.

What I’ll go to do is leverage this library for the queries and implement a custom service to manage the entities saving.

ODataResource factory

The first factory that I want to implement is an object that wrap the basic ODataResources module and expose the CRUD operations of the entity.

First of all, I need to install the library, and you can refer to the GitHub project for any detail.

Than, I can start with the implementation and creating the new module:


(function(window, angular) {
'use-strict';
angular.module('odataResourcesModule', ['ui.router', 'ODataResources'])

.factory('odataResource', function ($odataresource, $http, $q) {

function odataResource(serviceRootUrl, resourcePath, key) {
this.serviceRootUrl = serviceRootUrl;
this.resourcePath = resourcePath;
this.key = key;

this._odataResource = $odataresource(serviceRootUrl + '/' + resourcePath, {}, {}, {
odatakey: key,
isodatav4: true
});

angular.extend(this._odataResource.prototype, {
'$patch': function () {
var defer = $q.defer();

var req = {
method: 'PATCH',
url: serviceRootUrl + '/' + resourcePath + '(' + this.Id + ')',
data: this
};

$http(req).then(function (data) {
defer.resolve(data);
}, function (error) {
defer.reject(error);
});

return defer.promise;
}
});
}

.....

The factory has a constructor where I pass three parameters, the ServiceRootUrl that is the first part of the url (in my case odata), the resourcePath that identify the entity (Blogs) and the key of the table.

Then I configure the $odataresource with these parameters and I setup the odata v4 as well.

At the end I extend the OdataResource prototype because this library doesn’t provide the implementation for the PATCH verb, I need to implement it with my custom function.

So far so good, now I want to expose some methods to queries the resource or retrieve a single entity:


odataResource.prototype.getResource = function () {
return this._odataResource.odata();
}

odataResource.prototype.get = function (id) {
var defer = $q.defer();

this._odataResource.odata().get(id, function (data) {
data._originalResource = angular.copy(data);
defer.resolve(data);
}, function (error) {
defer.reject(error);
});

return defer.promise;
}

With the getResource method I implement a getter for the resource and allow the caller to execute the queries.

The get method deserves a particular explanation, once the single entity is retrieved, I make copy of the original entity and assign that to a new private property named _originalResource.

This will allow me two check the values that will be changed on the entity, and compose the object that will be sent with the patch method.

Now I can implement the others methods to add, update and delete the entity:


odataResource.prototype.new = function () {
return new this._odataResource();
}

odataResource.prototype.add = function (resource) {
var defer = $q.defer();

resource.$save(function (data) {
data._originalResource = angular.copy(data);
defer.resolve(data);
}, function (error) {
defer.reject(error);
});

return defer.promise;
}

odataResource.prototype.update = function (resource) {
var defer = $q.defer();

var self = this;
resource.$patch().then(function () {
self.get(resource[self.key]).then(function (data) {
defer.resolve(data);
});
}, function (error) {
defer.reject(error);
});

return defer.promise;
}

odataResource.prototype.delete = function (resource) {
var defer = $q.defer();

resource.$delete(function (data) {
defer.resolve(data);
}, function (error) {
defer.reject(error);
});

return defer.promise;
}

Like the get method, I do a copy of the entity in the add method as well.

Now I have a factory that is able to query Web API OData services and manage the crud operations and I can proceed with some business logic.

ODataGenericResource factory

The first step is define the new factory:


.factory('odataGenericResource', function ($q, odataResource) {

function odataGenericResource(serviceRootUrl, resourcePath, key) {
this.odataResource = new odataResource(serviceRootUrl, resourcePath, key);
}

In the constructor I create a new instance of the ODataResource factory, in order to leverage the methods implemented above.

Based on the id parameter, now I implement a get method that will create a new resource or perform a get from a Web API OData service:


odataGenericResource.prototype.get = function (id) {
if (id === '') {
var defer = $q.defer();
defer.resolve(this.odataResource.new());

return defer.promise;
} else {
return this.odataResource.get(id);
}
}

If an external service will call this method with an empty id will receive a new resource, otherwise will receive the entity, if exists.

Now I need to implement the save method:


odataGenericResource.prototype.isChanged = function (resource) {
var isChanged = false;
for (var propertyName in resource) {
if (isEntityProperty(propertyName) && resource._originalResource[propertyName] !== resource[propertyName]) {
isChanged = true;
}
}

return isChanged;
}

odataGenericResource.prototype.getObjectToUpdate = function (resource) {
var object = this.odataResource.new();
object[this.odataResource.key] = resource[this.odataResource.key];

for (var propertyName in resource) {
if (isEntityProperty(propertyName) && resource._originalResource[propertyName] !== resource[propertyName]) {
object[propertyName] = resource[propertyName];
}
}

return object;
}

odataGenericResource.prototype.save = function(resource) {
if (!resource._originalResource) {
return this.odataResource.add(resource);
} else if (this.isChanged(resource)) {
var object = this.getObjectToUpdate(resource);
return this.odataResource.update(object);
} else {
var defer = $q.defer();
defer.resolve(resource);

return defer.promise;
}
}

I need some methods, to check the state of the entity.

The IsChanged method check if any property of the entity is changed, leveraging the _originalResource property.

The second method prepare the effective object to save, with only the properties that has been changed.

The save method check if the entity is new (it doesn’t have the _originalResource property) or not; based on that, it will be added or saved.

The delete method doesn’t have particular stuff and we can now take a look at the using of this factory in the application.

Application

I can use this factory in any angular module that needs to manage crud operations for an entity.

For example, in a blogsModule, I can define a factory like this:


(function (window, angular) {
'use-strict';
angular.module('blogsModule', ['ui.router', 'odataResourcesModule'])
.factory('blogsService', function ($http, odataGenericResource) {
return new odataGenericResource('odata', 'Blogs', 'Id');
})

And now in the controller:


.controller('blogsCtrl', function ($scope, $state, blogsService) {

$scope.new = function() {
$state.go("home.blog", { id: null });
};

$scope.detail = function(id) {
$state.go("home.blog", { id: id });
};

$scope.Blogs = blogsService.getOdataResource().query();
})
.controller('blogsDetailCtrl', function ($scope, $state, blogsService) {
var load = function (id) {
blogsService.get(id).then(function(data) {
$scope.Blog = data;
});
};

$scope.save = function () {
blogsService.save($scope.Blog).then(function(data) {
load(data.Id);
});
}

$scope.delete = function () {
blogsService.delete($scope.Blog).then(function () {
$scope.close();
});
};

$scope.close = function () {
$state.go("home.blogs");
};

load($state.params.id);
});

With few lines of code I can manage the calls to a Web API OData service, with the possibility do fluent odata queries.

You can find the source code here.

Advertisements
Consume Web API OData with ODataAngularResources

Consume Web API with an Angularjs service

This topic concerns a problem that I faced in these days, that was the building of an Angularjs service to consume Web API’s, witch in my case were implemented with OData protocol.

The start point are some Web API’s, one for every entity of the project, that they responds to a specific url, for example:

I wouldn’t want to implement a service for every single Web API that do the same operations, so the idea is implement a generic javascript class with the basic methods and a factory that generates instances of this class; every module will have an own instance with some custom options, such as the service url.

So what I want to do are two things, a generic class that implements commons methods for CRUD operations and then a factory that generates instances of this service.

Generic service

Angularjs has several provider that we can use to instantiate services; the provider is the lower level and is use usually to configure reusable services that can be used in different applications.

Factory and services are syntactic sugar on top of a provider, and allow us to define singleton services in our application; the last two are constant and value that they provides values.

One of the main debates on Angularjs is when we use a factory or a service.

The main difference from these is that in the first one we needs to return an instance of the service in this way:


(function (window, angular) {
'use-strict'
angular.module('odataModule', [])
.factory('odataService', [function() {
returns {
.....
}
}]);
})(window, window.angular)

In the second one, we don’t need to do this, the angular service deal with object instantiation:


(function (window, angular) {
'use-strict'
angular.module('odataModule', [])
.service('odataService', [function() {
.....
}]);
})(window, window.angular)

What I want to implement is a javacript class that will have these properties/methods:

  • A url property, the Web API reference
  • An entityClass property, is the the javascript object that represents the entity to be managed
  • A isNew property, that allow the service to understand that the object need to be added (post) or saved (patch)
  • A getEntities method that retrieves the list of the entities
  • A createEntity method that returns a instance of a new entity
  • A getEntity method to retrieves a single entity
  • A saveEntity method that deal with the post/patch of the entity
  • And finally a method deleteEntity

An angular service help in this work by letting me write cleaner code that factory; a concrete implementation is:


(function (window, angular) {
'use-strict'
angular.module('odataModule', [])
.constant('blogsUrl', '/odata/Blogs')
.constant('postsUrl', '/odata/Posts')
.service('odataService', ['$http', function($http) {
function Instance(url, entityObject) {
this.isNew = false;
this.url = url;
this.entityClass = entityObject;
}

Instance.prototype.getEntities = function () {
return $http.get(this.url);
}

Instance.prototype.createEntity = function() {
this.isNew = true;
return angular.copy(this.entityClass);
}

Instance.prototype.getEntity = function (id) {
return $http.get(this.url + '(guid\'' + id + '\')');
}

Instance.prototype.saveEntity = function (entity) {
if (this.isNew) {
this.isNew = false;
return $http.post(this.url, entity);
}
else
return $http.patch(this.url + '(guid\'' + entity.Id + '\')', entity);
}

Instance.prototype.deleteEntity = function (entity) {
return $http.delete(this.url + '(guid\'' + entity.Id + '\')');
}
this.GetInstance = function(url, entityObject) {
return new Instance(url, entityObject);
};
}]);
})(window, window.angular)

The Instance class is the implementation of the common methods that we needed.

The last row is the main difference from a factory; in a service, the container function is a javascript function with a constructor and the service returns an instance of it, so I can define a method GetInstance that will returns an instance of my custom class.

If I had used a factory, the last rows would be the following:


return {
GetInstance: function(url, entityObject) {
return new Instance(url, entityObject);
}

Much better the implementation with the service.

Factories of the entities

Now I need to define a specific factory for every entity:


(function (window, angular) {
'use-scrict';
angular.module('blogsModule', ['ui.router', 'odataModule'])
.factory('blogsFactory', ['odataService', 'blogsUrl', function (odataService, blogsUrl) {
var blogEntity = { Name: '', Url: '' };
return odataService.GetInstance(blogsUrl, blogEntity);
}])
})(window, window.angular)

So far so good, I have an instance of the service with specific parameters, and now I can use the factory for crud operations in my controller:


(function (window, angular) {
'use-scrict';
angular.module('blogsModule', ['ui.router', 'odataModule'])
....
.controller('blogsController', ['$scope', '$state', 'blogsFactory', function ($scope, $state, blogsFactory) {
$scope.Title = 'Blogs';

blogsFactory.getEntities().then(function (result) {
$scope.blogs = result.data.value;
});

$scope.create = function() {
$state.go('main.blog', { id: null });
};

$scope.edit = function (blog) {
$state.go('main.blog', { id: blog.Id });
};
}])
.controller('blogController', ['$scope', '$state', '$stateParams', 'odataService', function ($scope, $state, $stateParams, odataService) {
$scope.Title = 'Blog';
var service = new odataService.GetInstance('/odata/Blogs', { Name: '', Url: '' });

$scope.save = function () {
service.saveEntity($scope.blog).then(function () {
$state.go('main.blogs');
});
};

$scope.delete = function() {
service.deleteEntity($scope.blog).then(function () {
$state.go('main.blogs');
});
};

$scope.close = function() {
$state.go('main.blogs');
};

if ($stateParams.id === '')
$scope.blog = service.createEntity();
else {
odataService.getEntity($stateParams.id).then(function (result) {
$scope.blog = result.data;
});
}
}]);
})(window, window.angular)

With few lines of code I have managed the crud operations.

In my case the odata module can be improved with checks about the entity validations, by using the $metadata informations returned by the odata services and I can retrieve also the entity fields without passing those as parameters, but, anyway, this is a good starting point.

 

 

 

 

Consume Web API with an Angularjs service

Webpack with Angular2

In a previous post I spoke about the configurations to manage bundles in angular 2 with Systemjs.

For this purphose, the latest versions of Angular CLI uses webpack and we can use it as module bundler in the new angular 2/4 applications.

The reason of this choice is that webpack has a lot of plugins that they help us with a refined management of the modules bundling.

Entries

When we configure webpack, the first thing that we need to do is define the entries of the bundles.

Every bundle has the main entry point, that is the module where webpack start to build the bundle hierarchy.

I like to build two different bundle, the first one for the vendors libraries and the second one for the application modules.

The  main entry for the vendors is a typescript class that looks like this:


import '@angular/platform-browser';
import '@angular/platform-browser-dynamic';
import '@angular/core';
import '@angular/common';
import '@angular/http';
import '@angular/router';
import '@angular/animations';

import 'jquery';
import 'lodash';
import 'ng2-toastr';
import 'ng2-translate';
import 'reflect-metadata';
import 'zone.js';
import 'rxjs';

The second one is the main module for the app:


export { PostModule } from "./post.module";

Webpack is able to load these modules and build the dependencies of the childs descendans, and process them.

Loaders

Loaders are specific webpack tools that are able to process specific file types and to produce the right bundle outputs.

For example, in order to make webpack to be able to resolve the angular html templates or the router modules, or more simply to compile typescript files, specific loaders are needed.

Below you can see a bunch of loaders used in an Angular 2 application:


module: {
rules: [
{
test: /\.ts$/,
loaders: [
{
loader: 'awesome-typescript-loader',
options: { configFileName: 'tsconfig.json' }
}, 'angular2-template-loader', 'angular2-router-loader'
]
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)$/,
loader: 'file-loader?name=images/[name].[hash].[ext]'
},
{
test: /\.css$/,
exclude: helpers.root('src', 'app'),
loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: 'css-loader?sourceMap' })
},
{
test: /\.css$/,
include: helpers.root('src', 'app'),
loader: 'raw-loader'
}
]
}

Plugins

These are utilities that we can help us in some additional tasks of the webpack script.

For example, we would like to share a common chunk and we would want that the chunk, if used from different module of the application, is not repeated in the bundle but is present only once.

CommonsChunkPlugin deal with this work:


plugins: [

.....

new webpack.optimize.CommonsChunkPlugin({
name: ['vendor']
}),

.....

]

Another requirement could be write the script references in the index.html file of the application.

HtmlWebpackPlugin can help us in this work:


plugins: [

.....

new HtmlWebpackPlugin({
filename: 'index.html',
template: 'src/index.html',
chunks: ['app', 'vendor']
}),

new HtmlWebpackPlugin({
filename: 'index.admin.html',
template: 'src/index.admin.html',
chunks: ['app.admin', 'vendor']
}),

.....
]

Output

In this section we can configure the file results of the webpack process.

We have to produce these files in the public folder of the application; the output section is look like this:


output: {
path: helpers.root('wwwroot'),
filename: 'js/[name].js',
chunkFilename: 'js/[id].chunk.js'
}

 

You can find the source code here.

 

Webpack with Angular2

Translations in Angular 2

A common requirement in Angular 2 is configure and share a service used from all the components of the application.

In a multilanguage application, a service that we need to use is the provider for the language translations; obviously this module will be used in all the components, or at least in those that have an html template.

The service that we use is ng2-translate; what we need to do is installing the package, provide it with a shared module and use the translation service in the components.

Installation

First we install the package:

npm install ng2-translate –save

Once installed, we have to configure the package with a module loader like SystemJS (or Webpack):

(function (global) {
System.config({
paths: {
'npm:': 'node_modules/'
},
map: {
app: 'app',
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
.....
'ng2-translate': 'npm:ng2-translate/bundles/index.js'
},
packages: {
.....
}
});
})(this);

Now the package is installed and configured and we can going to provide the service.

Providing

As explained below, in order to provide the service we have to use a shared module of the application; we already have discussed in a previous post a module like that, and we can edit it:

import { NgModule, ModuleWithProviders, Optional, SkipSelf } from "@angular/core";
.....
import { TranslateModule } from "ng2-translate";
.....
@NgModule ({
imports: [
.....
],
exports: [
.....
TranslateModule,
.....
]
})
export class SharedModule {}

We have to export the TraslateModule in order to make it shared; otherwise the others modules won’t be able to use it.

Now the translate module is provided and we can define the translations; by using the default configuration, we can create the i18n folder in the root of the project and create a json file for every language supported.

For example, en.json:

{
"NEW": "New",
"SAVE": "Save",
"CLOSE": "Close",
"DELETE": "Delete",
"NAME": "Name",
"ADDRESS": "Address",
"ATTACHMENT": "Attachment",
"ATTACHINVOICE": "Attach invoice",
"CITY": "City",
"ZIP": "Zip",
"DISTRICT": "District",
"COUNTRY": "Country",
"NUMBER": "Number",
"YEAR": "Year",
"CUSTOMER": "Customer",
"EMISSIONDATE": "Emission Date",
"DUEDATE": "Due Date",
"PAYMENTDATE": "Payment Date",
"CUSTOMERSLOADED": "Customers loaded successfully",
"CUSTOMERSAVED": "Customer saved",
"CUSTOMERDELETED": "Customer deleted",
"SEARCH": "Search",
"INVOICESLOADED": "Invoices loaded successfully",
"INVOICESAVED": "Invoice saved",
"INVOICEDELETED": "Invoice deleted"
}

Now we are ready to use the translations in the components of the application.

Translations

The service that make the work of translation is the TranslateService, and we import it:

import { Component, OnInit } from "@angular/core";
import { TranslateService } from "ng2-translate";
.....
@Component({
moduleId: module.id,
selector: "customer",
templateUrl: "customer.component.html"
})
export class CustomerComponent implements OnInit {
constructor(private customerService: CustomerService, private alertService: AlertService, private searchService: SearchService, <strong>private translateService: TranslateService</strong>) {}
public Load() {
this.alertService.isLoading = true;
this.customerService.GetAll().subscribe(
(data) => {
this.alertService.isLoading = false;
this.customers = data;
this.customer = null;
this.translateService.get("CUSTOMERSLOADED").subscribe((res: string) => {
this.alertService.Success(res);
});
},
(error) => this.alertService.Error(error));
}
.....
}

In this code, we inject the service in the component constructor and we use it to translate the CUSTOMERLOADED resource and show an alert message.

Another purpose of the translation service is translate the labels of a view:

<div [hidden]="edit">
<input type="button" class="btn btn-primary" value="New" (click)="New()" />
<table class="table table-striped">
<thead>
<tr>
<th>
{{ "NAME" | translate }}</th>
<th>
{{ "ADDRESS" | translate }}</th>
<th>
{{ "CITY" | translate }}</th>
</tr>
</thead>
<tbody>
.....</tbody>
</table>
</div>
.....

Here you can find the github repository with the source code.

 

Translations in Angular 2

Mandatory fields validation with knockoutjs extenders

Knockout is a lightweight javascript library that help us to bind the UI with a model and build rich web UI interactions.

The main behaviour of this library are the observable variables, that allow us to make a bidirectional binding between the html fields and the view model of the page.

An interesting feature is extend the observable variables, enriching them with some aditional functionalities; in this example we’ll extend the observable variables with a control for the mandatory fields.

The extender

The extenders allow us to “extend” an observable variable with some behaviours; in this case, we want to add a control for the mandatory fields:


ko.extenders.required = function(target, message) {
target.hasError = ko.observable(false);
target.errorMessage = ko.observable(message || "The field is mandatory.");

function validate(value) {
target.hasError(value ? false : true);
}

validate(target());
target.subscribe(validate);

return target;
};

The function accept two parameters, the target object and the message to show and has the related properties.

The function “validate” set the correct value of hasError property, is called when the main function is loaded and it has been binded to the target object.

We’ll use this extender in our web page.

The view model

We define the view model of the page.


function ViewModel() {
var self = this;

self.FirstName = ko.observable("").extend({ required: "" });
self.LastName = ko.observable("").extend({ required: "" });

self.OnSubmit = ko.observable(false);
self.OnSendData = ko.observable(false);

self.Submit = function () {
self.OnSubmit(true);

if (!self.FirstName.hasError() && !self.LastName.hasError()) {
self.SendData();
}
}

self.Unsubmit = function () {
self.OnSubmit(false);
}

self.SendData = function () {
self.OnSendData(true);
}
}

Has you can see, we are using the extender in the properties definition; we extend the FirstName and LastName properties with the “required” extender; the syntax:

self.FirstName = ko.observable(“”).extend({ required: “” });

means that we pass to the extender two parameters, the first one is the target property (the observable) and the second one is the message (the empty string).

In the submit function we check the value of the hasError property and then we send the data.

The page

Now we are ready to implement the web page.


<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />

		<link rel="stylesheet" type="text/css" href="Content/main.css"/>
<script type="text/javascript" src="scripts/jquery-3.1.1.js"></script>
 <script type="text/javascript" src="scripts/knockout-3.4.0.js"></script>
<script type="text/javascript" src="scripts/extenders.js"></script>
 <script type="text/javascript" src="scripts/viewModel.js"></script>

<script type="text/javascript">
 $(function () {
 var vm = new ViewModel();
 ko.applyBindings(vm);
 });
 </script>
</head>
<body>
<script type="text/html" id="field-error">


<div>
 <input type="text" data-bind="value: field, css: { fieldError: $root.OnSubmit() && field.hasError }" />
 <span data-bind="text: field.errorMessage, visible: $root.OnSubmit() && field.hasError" class="labelError"></span>
</div>


 </script>
<div>
<label>First name</label>
<div data-bind="template: { name: 'field-error', data: { field: FirstName } }"></div>
</div>
<div>
<label>Last name</label>
<div data-bind="template: { name: 'field-error', data: { field: LastName } }"></div>
</div>
<div>
<input type="button" data-bind="click: Submit" value="submit" /></div>
<div>
<label data-bind="visible: OnSendData">Send Data!</label></div>
</body>
</html>

We have defined a template “field-error” that is composed by an input text field and by an error label.

The field has a bind to the value and to the css as well:

<input type=”text” data-bind=”value: field, css: { fieldError: $root.OnSubmit() && field.hasError }” />

The css is conditioned to the OnSubmit event and to the hasError property of the extender.

If all of these properties are true, the fieldError class need to be applied.

The error label is similar:

<span data-bind=”text: field.errorMessage, visible: $root.OnSubmit() && field.hasError” class=”labelError”></span>

The only difference is the text, binded to the errorMessage property of the extender, that we have initialized to an empty string in the view model above.

Then we use the template to define the fields:

Finally, the small css used in this example:


.labelError {
color: #ff0000;
}

.fieldError {
border-color: #ff0000;
}

 

Mandatory fields validation with knockoutjs extenders

Bootstrapping an Angular 2 application

In an Angular 2 application we have different options to load application and modules, and one of these is SystemJS.

This is an open source project that give us the ability to load bunch of modules and define for each one the corresponding default main module.

Therefore you can use this library to define a default main module for an Angular 2 application; the first step is install this with npm, by adding as a dependency in the package.json file of the project:


{
 ...
 },
 "license": "ISC",
 "dependencies": {
 ...
 "systemjs": "0.19.27",
 ...
 },
 "devDependencies": {
 ...
 }
}

This library allows you to configure you application startup and defaults by using a specific json file.

The file that we need to create is called systemjs.config.js:

(function (global) {
 var map = {
 'app': 'app',
 ...
 };
 var packages = {
 'app': { main: 'main.js', defaultExtension: 'js' },
 ...
 };
var config = {
 map: map,
 packages: packages
 };
 System.config(config);
})(this);

Notice that one of the packages property is app, that is our app selector, and for that we specify the main property, that is the default loader; you can also use this file to configure other stuff, such as bundling or other default main modules.

The last step is create the loader file, that we can call, for example, Main.ts:

import { bootstrap } from '@angular/platform-browser-dynamic';
import { AppComponent } from './App.Component';
bootstrap(AppComponent);

With the last row, we will load as default the AppComponent, that is the main component of our app.

Finally, this is the App.Component.ts file:

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

@Component({
 selector: 'app',
 templateUrl: 'app/views/app.html'
})

export class AppComponent {
 title: string = 'New App';
}

The selector property of the component is the value that we have assigned in the fourth row of the systemjs.config.js above.

 

Bootstrapping an Angular 2 application