Building Your First Angular App

To avoid confusion, Angular 1 and all its releases are combined in a short name AngularJS, and Angular 2 and all subsequent versions are usually referred to simply as Angular. As a matter of fact, Angular 6 is already released. There’s a great demand for Angular 4 developers as well as for those who use other releases, so, you don’t have to instantly migrate to a newer release just to keep up with the market.

Be an Angular Dev

Quick Dive into the History

The history of Angular began in October 2010. The team from Google developed a JavaScript-based framework that later became known to the world as Angular 1. As soon as the framework started to gain popularity as a tool for developing dynamic web pages, its shortcomings, sometimes very critical, also started to reveal. Therefore, Angular 1 was rewritten from scratch, its architecture was changed, TypeScript became the main language, meant to provide all the features of OOP and in 2016 Angular 2 was released.

Pre-Install

The way an Angular application should be built directly depends on what is required to be done. Let’s imagine that we need to get a list of users and display them on the screen. In this tutorial, we want our Angular application not only to solve the task but to remain extensible and universal. We also want our code to be intuitive.

Like with any other Angular application, we would be using the Angular CLI (Command Line Interface) tool to create it. To be able to do this, we need npm which comes with Node.js. Then, let’s install the Angular CLI using npm with the -g (or --global) option. Open terminal and enter this command:

1
npm install -g @angular/cli

Now create an empty project using the Angular CLI:

1
ng new DummyApp

At this stage, the project looks like this:

Initial Angular App File and Folder Structure

Files and Folders Structure

The architecture of Angular is based on modules that combine services, components and other modules. Everything starts with the most important module, which is always named app.module.ts. Note the ts file extension. You’ll want to know TypeScript if you’re going to write Angular apps. This is the main container for other modules, services and components.

Our future “DummyApp” will consist of several modules. Each module will be responsible for a particular logical entity and contain components, services and models for this entity. We would separately create a directory for the shared module that contains the components required for a number of modules or even all modules at the same time. We need to import it into each module created by us.

Also, we would need to create a common directory, where there will be files of abstract classes. But first things first.

At this stage the project looks like this:

Current File and Folder Structure

Main App Build Principles

First of all, we need to create a file for the User entity. This will be a regular class with several properties, a method for obtaining a full user name and its factory creating instances of the User class. I initialize all properties with null to be able to create an instance of the User class without filling it with data.

/app/modules/users/models/User.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
export class User {
public static factory(data: object): User {
const user = <User>data;
return new this(
user.id,
user.login,
user.type
);
}

constructor(
public id: string = null,
public login: string = null,
public type: string = null
) {
}

public get fullName(): string {
return `${this.type}: ${this.login}`;
}
}

Next, we need to create a service to get a list of users. As it will work with a REST API, we call it RestService. The operations for getting the lists of entities or one entity by its ID are fairly generic. So, I’ll put them in a separate abstract class. To do this, in the common directory, create the services directory where the AbstractRestService will be located in abstract.rest.service.ts:

/app/common/services/abstract.rest.service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import {HttpClient} from '@angular/common/http';
import {Observable} from 'rxjs/Observable';
import {DummyConfig} from '../Config';
import {map} from 'rxjs/operators';

export abstract class AbstractRestService<T> {
protected url: string;
public abstract factory(data:any): T;

protected constructor (
public http: HttpClient
) {
}

getList(): Observable<T[]> {
return this.http.get<T[]>(`${DummyConfig.Domain}/${this.url}`).pipe(
map((data: T[]) => {
let items = data || [];
if (items.length) {
items = items.map((item) => this.factory(item));
}
return items;
})
);
}
}
/app/common/Config.ts
1
2
3
export class DummyConfig {
public static Domain = 'https://api.github.com';
}

The url parameter will store the string for the API, while the factory function will return a new instance of the class we need. The getList() method will call a standard HTTP request but we will dynamically generate a full URL and create an array of instances of the class we need.

Let’s create a UsersService in the users module that will inherit from AbstractRestService. We will specify the desired url in the constructor and implement factory as a function that will return an instance of the User class.

/app/modules/users/services/users.service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import {HttpClient} from '@angular/common/http';
import {AbstractRestService} from '../../../common/services/abstract.rest.service';
import {User} from '../models/User';
import {Injectable} from '@angular/core';

@Injectable()
export class UsersService extends AbstractRestService<User> {
public factory(data): User {
return User.factory(data);
}

constructor(
http: HttpClient
) {
super(http);
this.url = 'users';
}
}

It’s the perfect time to create a component for displaying the list of users. But, in the future, another entity may appear and, quite possibly, we will need to output one more list. Therefore, first create an abstract list component. In common, let’s create the components/list directory, and put abstract.list.component.ts in it:

/app/common/components/list/abstract.list.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import {AbstractRestService} from '../../services/abstract.rest.service';
import {OnInit} from '@angular/core';

export abstract class AbstractListComponent<T> implements OnInit {
public items: T[];

protected constructor(
protected service: AbstractRestService<T>
) {}

ngOnInit(): void {
this.getList();
}

public getList(): void {
this.service.getList().subscribe((items: T[]) => this.items = items);
}
}

Now, let’s create the concrete implementation of the UsersList component:

/app/modules/users/components/list/list.component.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import {Component} from '@angular/core';
import {UsersService} from '../../services/users.service';
import {User} from '../../models/User';
import {AbstractListComponent} from '../../../../common/components/list/abstract.list.component';

@Component({
selector: 'users-list',
templateUrl: 'list.component.html'
})
export class UsersList extends AbstractListComponent<User> {
constructor(
service: UsersService
) {
super(service)
}
}
/app/modules/users/components/list/list.component.html
1
2
3
4
5
<ul>
<li *ngFor="let user of items">
{{user.fullName}}
</li>
</ul>

Now the structure looks like this:

Final File and Folder Structure

Run the app and the results look like this:

Results in the Browser

If required, you can create list components for any entities. While file names and entity models will change, encapsulation and behavior will persist. The directory structure may vary slightly but should always remain minimally deep and well-remembered. The general logic is created separately. Thus it can be easily extended or modified. Getting deeper into the TypeScript and learning more about object-oriented programming would let you open even more ways of solving tasks.

And remember, you can always do better!

By Anastasia Stefanuk of Mobilunity

Author: Guest

Author: Guest Sometimes someone asks if they can write for the blog. They may want to just work on their own writing chops, get their foot in the blogging door, or maybe they want to show off something they've done. In any case, they are a guest author and this post happens to be written by one; please enjoy the hard work they've done to put this article together.