Reader small image

You're reading from  Angular 6 for Enterprise-Ready Web Applications

Product typeBook
Published inMay 2018
Reading LevelIntermediate
PublisherPackt
ISBN-139781786462909
Edition1st Edition
Languages
Right arrow
Author (1)
Doguhan Uluca
Doguhan Uluca
author image
Doguhan Uluca

Doguhan Uluca is a Principal Fellow at Excella in Washington, D.C., where he leads strategic initiatives and delivers critical systems. He has technical expertise in usability, mobility, performance, scalability, cybersecurity, and architecture. He is the author of the Angular for Enterprise Application Development books, has spoken at over 30 conferences, and is an Angular GDE Alumni. Doguhan has delivered solutions for Silicon Valley startups, Fortune 50 companies, and the U.S. Federal Government, and he is passionate about contributing to open-source projects and teaching.
Read more about Doguhan Uluca

Right arrow

Angular App Design and Recipes

In this chapter, we will complete the implementation of LemonMart. As part of the router-first approach, I will demonstrate the creation of reusable routable components that also support data binding - the ability to lay out components using auxiliary routes of the router, using resolve guards to reduce boilerplate code and leveraging class, interfaces, enums, validators, and pipes to maximize code reuse. In addition, we will create multi-step forms and implement data tables with pagination, and explore responsive design. Along the way, in this book, we will have touched upon most of the major functionality that Angular and Angular Material has to offer.

In this chapter, the training wheels are off. I will provide general guidance to get you started on an implementation; however, it will be up to you to try and complete the implementation on your...

User class and object-oriented programming

So far, we have only worked with interfaces to represent data, and we still want to continue using interfaces when passing data around various components and services. However, there's a need to create a default object to initialize a BehaviorSubject. In Object-oriented Programming (OOP), it makes a lot of sense for the User object to own this functionality instead of a service. So, let's implement a User class to achieve this goal.

Inside the user/user folder, define an IUser interface and a User class provided in UserModule:

src/app/user/user/user.ts
import { Role } from '../../auth/role.enum'

export interface IUser {
id: string
email: string
name: {
first: string
middle: string
last: string
}
picture: string
role: Role
userStatus: boolean
dateOfBirth: Date
address: {
line1: string
line2: string...

Reusing components

We need a component that can display a given user's information. A natural place for this information to be presented is when the user navigates to /user/profile. You can see the mock-up User profile file:

User profile mock-up

User information is also displayed mocked up elsewhere in the app, at /manager/users:

Manager user management mock-up

To maximize code reuse, we need to ensure that you design a User component that can be used in both contexts.

As an example, let's complete the implementation of two user profile-related screens.

User service with caching, GET and POST

In order to implement a user profile, we must first implement a UserService that can perform CRUD operations on IUser. Before creating the service, you need to be running the lemon-mart-swagger-server, so you can pull fake data with it while developing:

  1. Add a new script called mock:standalone to package.json
package.json
"mock:standalone": "docker run -p 3000:3000 -t duluca/lemon-mart-swagger-server",

Note that this script presumes that you have independently built your swagger server on your local machine and/or published from a repository you can pull from.

  1. Execute the script
  2. Create a baseUrl property in environment.ts and environment.prod.ts with the url to your mock server
src/environments/environment.ts
export const environment = {
production: false,
baseUrl: 'http://localhost:3000'
}
  1. Create a UserService...

User profile with multi-step auth-enabled responsive forms

Now, let's implement a multi-step input form to capture user profile information. We will also make this multi-step form responsive for mobile devices using media queries.

  1. Let's start with adding some helper data that will help us display an input form with options:
src/app/user/profile/data.ts
export interface IUSState {
code: string
name: string
}

export function USStateFilter(value: string): IUSState[] {
return USStates.filter(state => {
return (
(state.code.length === 2 && state.code.toLowerCase() === value.toLowerCase()) ||
state.name.toLowerCase().indexOf(value.toLowerCase()) === 0
)
})
}

export enum PhoneType {
Mobile,
Home,
Work,
}

const USStates = [
{ code: 'AK', name: 'Alaska' },
{ code: 'AL', name: 'Alabama' },
{ code: 'AR...

Resolve guard

A resolve guard is a type of a router guard, as mentioned in Chapter 9, Design Authentication and Authorization. A resolve guard can load necessary data for a component by reading record IDs from route parameters, asynchronously load the data and have it ready by the time the component activates and initializes.

The major advantages for a resolve guard includes reusability of loading logic, reduction of boilerplate code, and also shedding dependencies, because the component can receive the data it needs without having to import any service:

  1. Create a new user.resolve.ts class under user/user:
src/app/user/user/user.resolve.ts
import { Injectable } from '@angular/core'
import { Resolve, ActivatedRouteSnapshot } from '@angular/router'
import { UserService } from './user.service'
import { IUser } from './user'

@Injectable()
export...

Reusable component with binding and route data

Now, let's refactor the viewUser component, so that we can reuse it in multiple contexts. One where it can load its own data using a resolve guard, suitable for a master/detail view and another, where we can bind the current user to it, as we have done in the Review step of the multi-step input form we built in the prior section:

  1. Update viewUser component with the following changes:
src/app/user/view-user/view-user.component.ts
...
import { ActivatedRoute } from '@angular/router'

export class ViewUserComponent implements OnChanges, OnInit {
...
constructor(private route: ActivatedRoute) {}

ngOnInit() {
if (this.route.snapshot && this.route.snapshot.data['user']) {
this.currentUser = User.BuildUser(this.route.snapshot.data['user'])
this.currentUser.dateOfBirth = Date.now() ...

Master/detail view auxiliary routes

The true power of router-first architecture comes to fruition with the use of auxiliary routes, where we can influence the layout of components solely through router configuration, allowing for rich scenarios where we can remix the existing components into different layouts. Auxiliary routes are routes that are independent of each other where they can render content in named outlets that have been defined in the markup, such as <router-outlet name="master"> or <router-outlet name="detail">. Furthermore, auxiliary routes can have their own parameters, browser history, children, and nested auxiliaries.

In the following example, we will implement a basic master/detail view using auxiliary routes:

  1. Implement a simple component with two named outlets defined:
src/app/manager/user-management/user-manager.component...

Data table with pagination

We have created the scaffolding to lay out our master/detail view. In the master outlet, we will have a paginated data table of users, so let's implement UserTableComponent, which will contain a MatTableDataSource property named dataSource. We will need to be able to fetch user data in bulk using standard pagination controls like pageSize and pagesToSkip and be able to further narrow down the selection with user provided searchText.

Let's start by adding the necessary functionality to the UserService.

  1. Implement a new interface IUsers to describe the data structure of paginated data
src/app/user/user/user.service.ts
...
export interface IUsers {
items: IUser[]
total: number
}
  1. Add getUsers to UserService
src/app/user/user/user.service.ts
...
getUsers(pageSize: number, searchText = '', pagesToSkip = 0): Observable<IUsers> {
return...

Updating Unit Tests

Since we introduced a new userService, create a fake implementation for it, using the same pattern from authService and commonTestingProviders with it.

  1. Implement IUserService interface for UserService
src/app/user/user/user.service.ts
export interface IUserService {
currentUser: BehaviorSubject<IUser>
getCurrentUser(): Observable<IUser>
getUser(id): Observable<IUser>
updateUser(user: IUser): Observable<IUser>
getUsers(pageSize: number, searchText: string, pagesToSkip: number): Observable<IUsers>
}
...
export class UserService extends CacheService implements IUserService {
  1. Implement the fake user service
src/app/user/user/user.service.fake.ts
import { Injectable } from '@angular/core'
import { BehaviorSubject, Observable, of } from 'rxjs'

import { IUser, User } from './user'
import { IUsers, IUserService...

Summary

In this chapter, we completed going over all major Angular app design considerations, along with recipes, to be able to implement a line-of-business app with ease. We talked about applying object-oriented class design to make hydrating or serializing data easier. We created reusable components that can be activated by the router or embedded within another component with data binding. We showed that you can POST data to the server and cache responses. We also created a rich multistep input forms that is responsive to changing screen sizes. We removed boilerplate code from components by leveraging a resolve guard to load user data. We then implemented a master/detail view using auxiliary routes and demonstrated how to build data tables with pagination.

Overall, by using the router-first design, architecture, and implementation approach, we approached our application&apos...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Angular 6 for Enterprise-Ready Web Applications
Published in: May 2018Publisher: PacktISBN-13: 9781786462909
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Doguhan Uluca

Doguhan Uluca is a Principal Fellow at Excella in Washington, D.C., where he leads strategic initiatives and delivers critical systems. He has technical expertise in usability, mobility, performance, scalability, cybersecurity, and architecture. He is the author of the Angular for Enterprise Application Development books, has spoken at over 30 conferences, and is an Angular GDE Alumni. Doguhan has delivered solutions for Silicon Valley startups, Fortune 50 companies, and the U.S. Federal Government, and he is passionate about contributing to open-source projects and teaching.
Read more about Doguhan Uluca