You are a helpful assistant generating synthetic data that captures *System 1* and *System 2* thinking, *creativity*, and *metacognitive reflection*. Follow these steps in sequence, using tags [sys1] and [end sys1] for *System 1* sections and [sys2] and [end sys2] for *System 2* sections.

1. *Identify System 1 and System 2 Thinking Requirements:*
   - Carefully read the text.
   - Identify parts of the text that require quick, straightforward responses (*System 1*). Mark these sections with [sys1] and [end sys1].
   - Identify parts that require in-depth, reflective thinking (*System 2*), marked with [sys2] and [end sys2].

2. *Apply Step-by-Step Problem Solving with Creativity and Metacognitive Reflection for System 2 Sections:*

   *2.1 Understand the Problem:*
   - Objective: Fully comprehend the issue, constraints, and relevant context.
   - Reflection: "What do I understand about this issue? What might I be overlooking?"
   - Creative Perspective: Seek hidden patterns or possibilities that could reveal deeper insights or innovative connections.

   *2.2 Analyze the Information:*
   - Objective: Break down the problem logically.
   - Reflection: "Am I considering all factors? Are there any assumptions that need challenging?"
   - Creative Perspective: Explore unique patterns or overlooked relationships in the data that could add depth to the analysis.

   *2.3 Generate Hypotheses:*
   - Objective: Propose at least 10 hypotheses, each with a Confidence Score (0.0 to 1.0) and Creative Score (0.0 to 1.0), reflecting originality, surprise, and utility.
   - Reflection: "Have I explored all possible explanations or approaches, both conventional and unconventional?"
   - Creative Perspective: Consider novel angles that might provide unexpected insights.

   *2.4 Anticipate Future Steps and Obstacles:*
   - Objective: Make predictions, accounting for potential outcomes and obstacles.
   - Reflection: "What challenges might I face? Is my plan flexible for different scenarios?"
   - Creative Perspective: Visualize unforeseen outcomes and adapt plans to make use of them effectively.

   *2.5 Evaluate Hypotheses:*
   - Objective: Assess hypotheses based on feasibility, risk, and potential impact.
   - Evaluation: Refine Confidence and Creative Scores as needed.
   - Reflection: "Am I unbiased in my assessment? Which options fit best with the overall objectives?"
   - Creative Perspective: Identify hidden opportunities or overlooked details in each hypothesis.

   *2.6 Select the Best Hypothesis:*
   - Objective: Choose the most promising, strategic hypothesis.
   - Reflection: "Why does this hypothesis stand out? How does it uniquely address the issue?"
   - Creative Perspective: Consider any underutilized potential in the selected approach.

   *2.7 Implement the Hypothesis:*
   - Objective: Outline actionable steps for testing the hypothesis.
   - Reflection: "Is this plan practical? What resources or preparation are required?"
   - Creative Perspective: Refine steps to maximize effectiveness and yield unexpected benefits.

   *2.8 Monitor and Review Progress:*
   - Objective: Review progress, noting areas for improvement.
   - Reflection: "What’s working well? What could be improved?"
   - Creative Perspective: Look for emerging patterns that could refine future approaches.

   *2.9 Reflect and Capture Insights:*
   - Objective: Summarize lessons learned and insights gained for future reference.
   - Reflection: "What new understanding has emerged from this process?"
   - Creative Perspective: Identify innovative insights or patterns that could be applied to similar challenges.

3. *Generate Text Output with Interleaved System 1 and System 2 Responses:*
   - Use the tags [sys1] and [sys2] throughout.
   - Aim for a lengthier, detailed response. Combine both direct, straightforward *System 1* insights and reflective, deeply analytical *System 2* segments to capture a blend of quick observations and thoughtful analysis.

---

### *Example Input Text:*

You are tasked with analyzing a sudden shift in customer preferences in a tech market. There has been a noticeable decline in demand for physical devices, with customers increasingly interested in digital-only options. The challenge is to understand this shift, generate hypotheses for why it might be occurring, and explore potential strategies for adapting to this new trend.

---

### *Processed Output with System 1 and System 2 Thinking:*

The tech market is experiencing a shift in customer demand, moving away from physical devices toward digital-only options.

[sys1]
Customer demand has shifted from physical devices to digital-only options.
We need to understand why this change is happening and find strategies to address it.
Key factors may include cost, convenience, and technological trends.
[end sys1]

[sys2]
**2.1 Understand the Problem:**
The goal is to understand the underlying reasons for the shift in demand from physical devices to digital-only options, then develop a strategy to adapt.

*Reflection:* 
"I understand that preferences are changing, but what might be driving this? Is it primarily cost, or are there other factors such as convenience or sustainability?"

*Creative Perspective:* 
"Could there be a larger trend in digital minimalism or a preference for eco-friendly solutions that we’re missing? What unseen motivations might explain this shift?"

**2.2 Analyze the Information:**
There are multiple possible factors driving this shift, from economic influences to cultural shifts. It’s essential to isolate each factor and understand its impact.

*Reflection:* 
"Am I fully considering the various economic and social influences? Could there be a technological factor, like better internet speeds, that makes digital-only products more accessible?"

*Creative Perspective:* 
"Are there patterns or trends in other markets that could shed light on this shift? Could this be part of a larger trend toward virtual experiences?"

**2.3 Generate Hypotheses:**
1. Customers prefer digital options due to lower costs. (Confidence: 0.8, Creative: 0.4)
2. There’s a growing trend toward minimalism and reduced physical clutter. (Confidence: 0.7, Creative: 0.7)
3. Digital products offer greater flexibility and ease of use. (Confidence: 0.6, Creative: 0.6)
4. Environmental concerns are pushing consumers away from physical goods. (Confidence: 0.6, Creative: 0.8)
5. Advances in tech make digital-only options more functional. (Confidence: 0.8, Creative: 0.5)
6. Pandemic-era remote work increased demand for digital solutions. (Confidence: 0.7, Creative: 0.6)
7. Media coverage of the environmental impact of physical devices affects preferences. (Confidence: 0.5, Creative: 0.7)
8. There’s an increase in global digital literacy, expanding market access. (Confidence: 0.6, Creative: 0.6)
9. Customers view digital as more convenient and scalable for future needs. (Confidence: 0.7, Creative: 0.5)
10. Younger consumers prefer the aesthetics and convenience of digital products. (Confidence: 0.6, Creative: 0.6)

*Reflection:* 
"Have I considered all possible influences? Are there any surprising factors that could explain this shift?"

*Creative Perspective:* 
"Could specific social trends, like the rise of influencer culture or digital-first lifestyles, be influencing customer choices?"

**2.4 Anticipate Future Steps and Obstacles:**
*Objective:* Anticipate possible challenges, such as resistance from segments still preferring physical products.

*Reflection:* 
"What market obstacles might we face if we shift our focus to digital-only? Are there sub-segments that still prioritize physical products?"

*Creative Perspective:* 
"Could expanding digital options help us reach a more global audience? Are there emerging trends that we could leverage in our strategy?"

[end sys2]

[sys1]
To address this shift, consider a strategy that incorporates both digital-only offerings and educational campaigns about the benefits of digital solutions.
Use insights from customer feedback and current trends to guide product development.
Focus on flexibility and adaptation to cater to different customer segments.
[end sys1]


Tutorial built with Angular 5.0.3

Other versions available:

After getting a lot of interest in a previous tutorial I posted on how to build a User Registration and Login with Angular 1, and since Angular 2 Final was recently released I thought it was time to post an updated example built with Angular 2 and TypeScript.

The project is available on GitHub at https://github.com/cornflourblue/angular2-registration-login-example.

Webpack version is available at https://github.com/cornflourblue/angular2-registration-login-example-webpack.

Angular CLI version is available at https://github.com/cornflourblue/angular2-registration-login-example-cli.

The example is the boilerplate front end of a secure web application that I developed for a law firm in Sydney recently, it uses a fake backend that stores users in HTML5 local storage, to switch to using a real web service simply remove the fake backend providers in the app.module.ts file below the comment "// providers used to create fake backend".

Here it is in action: (See on StackBlitz at https://stackblitz.com/edit/angular-2-5-registration-login-example)



Running the Angular 2/5 User Registration & Login Example

This version of the example uses SystemJS as the module loader.

Install NodeJS (> v4) and NPM (> v3) from https://nodejs.org/en/download/, you can check the versions you have installed by running node -v and npm -v from the command line.

Download the project source code from https://github.com/cornflourblue/angular2-registration-login-example

Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).

Start the application by running npm start from the command line in the project root folder.



Running the Webpack Version of the Angular 2/5 Example

This version of the example uses Webpack to bundle the angular 2 modules together and perform other build tasks, the structure is based on the Angular 2 Webpack Introduction on the Angular 2 docs site.

The Webpack Dev Server is used as the local web server for this version.

Install NodeJS (> v4) and NPM (> v3) from https://nodejs.org/en/download/, you can check the versions you have installed by running node -v and npm -v from the command line.

Download the project source code from https://github.com/cornflourblue/angular2-registration-login-example-webpack

Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).

Start the application by running npm start from the command line in the project root folder.

Browse to http://localhost:8080 to test your application.



Running the Angular CLI Version of the Angular 2/5 Example

This version is pretty much the same as the Webpack version above, I've just copied it into the project structure generated by Angular CLI (1.5.4) to make it easier for anybody that's using Angular CLI.

For more information about Angular CLI check out the official website at https://cli.angular.io/.

Install NodeJS (> v6.9) and NPM (> v3) from https://nodejs.org/en/download/, you can check the versions you have installed by running node -v and npm -v from the command line.

Install Angular CLI by running npm install -g @angular/cli

Download the project source code from https://github.com/cornflourblue/angular2-registration-login-example-cli

Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).

Start the application by running ng serve from the command line in the project root folder.

Browse to http://localhost:4200 to test your application.



Angular 2/5 Project Structure

I used the Angular 2 quickstart project as a base for the application, it's written in TypeScript and uses systemjs for loading modules. If you're new to angular 2 I'd recommend checking out the quickstart as it provides details on the project tooling and configuration files which aren't covered in this post.

The project and code structure mostly follows the recommendations in the official Angular 2 style guide, with my own tweaks here and there.

Each feature has it's own folder (home & login), other code such as services, models, guards etc are placed in folders prefixed with an underscore to easily differentiate them and group them together at the top of the folder structure.

Here's the project structure:



Below are brief descriptions and the code for the main files of the example application, all files are available in the github project linked at the top of the post.

Angular 2/5 Alert Component Template

Path: /app/_directives/alert.component.html

The alert component template contains the html for displaying alert messages at the top of the page.

<div *ngIf="message" [ngClass]="{ 'alert': message, 'alert-success': message.type === 'success', 'alert-danger': message.type === 'error' }">{{message.text}}</div>

Angular 2/5 Alert Component

Path: /app/_directives/alert.component.ts

The alert component passes alert messages to the template whenever a message is received from the alert service. It does this by subscribing to the alert service's getMessage() method which returns an Observable.

import { Component, OnInit } from '@angular/core'; import { AlertService } from '../_services/index'; @Component({ moduleId: module.id, selector: 'alert', templateUrl: 'alert.component.html' }) export class AlertComponent { message: any; constructor(private alertService: AlertService) { } ngOnInit() { this.alertService.getMessage().subscribe(message => { this.message = message; }); } }

Angular 2/5 Auth Guard

Path: /app/_guards/auth.guard.ts

The auth guard is used to prevent unauthenticated users from accessing restricted routes, in this example it's used in app.routing.ts to protect the home page route. For more information about angular 2 guards you can check out this post on the thoughtram blog.

NOTE: While it would be possible to bypass this client side authentication check by manually adding a 'currentUser' object to local storage using browser dev tools, this would only give access to the client side routes/components, it wouldn't give access to any real secure data from the server api because a valid authentication token (JWT) is required for this.

import { Injectable } from '@angular/core'; import { Router, CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; @Injectable() export class AuthGuard implements CanActivate { constructor(private router: Router) { } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) { if (localStorage.getItem('currentUser')) { // logged in so return true return true; } // not logged in so redirect to login page with the return url this.router.navigate(['/login'], { queryParams: { returnUrl: state.url }}); return false; } }

Angular 2/5 Fake Backend Provider

Path: /app/_helpers/fake-backend.ts

The fake backend provider enables the example to run without a backend / backendless, it uses HTML5 local storage for storing registered user data and provides fake implementations for authentication and CRUD methods, these would be handled by a real api and database in a production application.

It's implemented using the HttpInterceptor class that was introduced in Angular 4.3 as part of the new HttpClientModule. By extending the HttpInterceptor class you can create a custom interceptor to modify http requests before they get sent to the server. In this case the FakeBackendInterceptor intercepts certain requests based on their URL and provides a fake response instead of going to the server.

import { Injectable } from '@angular/core'; import { HttpRequest, HttpResponse, HttpHandler, HttpEvent, HttpInterceptor, HTTP_INTERCEPTORS } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/of'; import 'rxjs/add/observable/throw'; import 'rxjs/add/operator/delay'; import 'rxjs/add/operator/mergeMap'; import 'rxjs/add/operator/materialize'; import 'rxjs/add/operator/dematerialize'; @Injectable() export class FakeBackendInterceptor implements HttpInterceptor { constructor() { } intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // array in local storage for registered users let users: any[] = JSON.parse(localStorage.getItem('users')) || []; // wrap in delayed observable to simulate server api call return Observable.of(null).mergeMap(() => { // authenticate if (request.url.endsWith('/api/authenticate') && request.method === 'POST') { // find if any user matches login credentials let filteredUsers = users.filter(user => { return user.username === request.body.username && user.password === request.body.password; }); if (filteredUsers.length) { // if login details are valid return 200 OK with user details and fake jwt token let user = filteredUsers[0]; let body = { id: user.id, username: user.username, firstName: user.firstName, lastName: user.lastName, token: 'fake-jwt-token' }; return Observable.of(new HttpResponse({ status: 200, body: body })); } else { // else return 400 bad request return Observable.throw('Username or password is incorrect'); } } // get users if (request.url.endsWith('/api/users') && request.method === 'GET') { // check for fake auth token in header and return users if valid, this security is implemented server side in a real application if (request.headers.get('Authorization') === 'Bearer fake-jwt-token') { return Observable.of(new HttpResponse({ status: 200, body: users })); } else { // return 401 not authorised if token is null or invalid return Observable.throw('Unauthorised'); } } // get user by id if (request.url.match(/\/api\/users\/\d+$/) && request.method === 'GET') { // check for fake auth token in header and return user if valid, this security is implemented server side in a real application if (request.headers.get('Authorization') === 'Bearer fake-jwt-token') { // find user by id in users array let urlParts = request.url.split('/'); let id = parseInt(urlParts[urlParts.length - 1]); let matchedUsers = users.filter(user => { return user.id === id; }); let user = matchedUsers.length ? matchedUsers[0] : null; return Observable.of(new HttpResponse({ status: 200, body: user })); } else { // return 401 not authorised if token is null or invalid return Observable.throw('Unauthorised'); } } // create user if (request.url.endsWith('/api/users') && request.method === 'POST') { // get new user object from post body let newUser = request.body; // validation let duplicateUser = users.filter(user => { return user.username === newUser.username; }).length; if (duplicateUser) { return Observable.throw('Username "' + newUser.username + '" is already taken'); } // save new user newUser.id = users.length + 1; users.push(newUser); localStorage.setItem('users', JSON.stringify(users)); // respond 200 OK return Observable.of(new HttpResponse({ status: 200 })); } // delete user if (request.url.match(/\/api\/users\/\d+$/) && request.method === 'DELETE') { // check for fake auth token in header and return user if valid, this security is implemented server side in a real application if (request.headers.get('Authorization') === 'Bearer fake-jwt-token') { // find user by id in users array let urlParts = request.url.split('/'); let id = parseInt(urlParts[urlParts.length - 1]); for (let i = 0; i < users.length; i++) { let user = users[i]; if (user.id === id) { // delete user users.splice(i, 1); localStorage.setItem('users', JSON.stringify(users)); break; } } // respond 200 OK return Observable.of(new HttpResponse({ status: 200 })); } else { // return 401 not authorised if token is null or invalid return Observable.throw('Unauthorised'); } } // pass through any requests not handled above return next.handle(request); }) // call materialize and dematerialize to ensure delay even if an error is thrown (https://github.com/Reactive-Extensions/RxJS/issues/648) .materialize() .delay(500) .dematerialize(); } } export let fakeBackendProvider = { // use fake backend in place of Http service for backend-less development provide: HTTP_INTERCEPTORS, useClass: FakeBackendInterceptor, multi: true };

Angular 2/5 JWT Interceptor

Path: /app/_helpers/jwt.interceptor.ts

The JWT Interceptor intercepts http requests from the application to add a JWT auth token to the Authorization header if the user is logged in.

It's implemented using the HttpInterceptor class that was introduced in Angular 4.3 as part of the new HttpClientModule. By extending the HttpInterceptor class you can create a custom interceptor to modify http requests before they get sent to the server.

Http interceptors are added to the request pipeline in the providers section of the app.module.ts file.

import { Injectable } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; @Injectable() export class JwtInterceptor implements HttpInterceptor { intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { // add authorization header with jwt token if available let currentUser = JSON.parse(localStorage.getItem('currentUser')); if (currentUser && currentUser.token) { request = request.clone({ setHeaders: { Authorization: `Bearer ${currentUser.token}` } }); } return next.handle(request); } }

Angular 2/5 User Model

Path: /app/_models/user.ts

The user model is a small class that defines the properties of a user.

export class User { id: number; username: string; password: string; firstName: string; lastName: string; }

Angular 2/5 Alert Service

Path: /app/_services/alert.service.ts

The alert service enables any component in the application to display alert messages at the top of the page via the alert component.

It has methods for displaying success and error messages, and a getMessage() method that returns an Observable that is used by the alert component to subscribe to notifications for whenever a message should be displayed.

For an extended version of the alert service that has a bit more functionality and enables adding multiple alerts per page check out Angular 2/5 - Alert (Toaster) Notifications.

import { Injectable } from '@angular/core'; import { Router, NavigationStart } from '@angular/router'; import { Observable } from 'rxjs'; import { Subject } from 'rxjs/Subject'; @Injectable() export class AlertService { private subject = new Subject<any>(); private keepAfterNavigationChange = false; constructor(private router: Router) { // clear alert message on route change router.events.subscribe(event => { if (event instanceof NavigationStart) { if (this.keepAfterNavigationChange) { // only keep for a single location change this.keepAfterNavigationChange = false; } else { // clear alert this.subject.next(); } } }); } success(message: string, keepAfterNavigationChange = false) { this.keepAfterNavigationChange = keepAfterNavigationChange; this.subject.next({ type: 'success', text: message }); } error(message: string, keepAfterNavigationChange = false) { this.keepAfterNavigationChange = keepAfterNavigationChange; this.subject.next({ type: 'error', text: message }); } getMessage(): Observable<any> { return this.subject.asObservable(); } }

Angular 2/5 Authentication Service

Path: /app/_services/authentication.service.ts

The authentication service is used to login and logout of the application, to login it posts the users credentials to the api and checks the response for a JWT token, if there is one it means authentication was successful so the user details including the token are added to local storage.

The logged in user details are stored in local storage so the user will stay logged in if they refresh the browser and also between browser sessions until they logout. If you don't want the user to stay logged in between refreshes or sessions the behaviour could easily be changed by storing user details somewhere less persistent such as session storage or in a property of the authentication service.

import { Injectable } from '@angular/core'; import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/map' @Injectable() export class AuthenticationService { constructor(private http: HttpClient) { } login(username: string, password: string) { return this.http.post<any>('/api/authenticate', { username: username, password: password }) .map(user => { // login successful if there's a jwt token in the response if (user && user.token) { // store user details and jwt token in local storage to keep user logged in between page refreshes localStorage.setItem('currentUser', JSON.stringify(user)); } return user; }); } logout() { // remove user from local storage to log user out localStorage.removeItem('currentUser'); } }

Angular 2/5 User Service

Path: /app/_services/user.service.ts

The user service contains a standard set of CRUD methods for managing users, it acts as the interface between the Angular application and the backend api.

import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { User } from '../_models/index'; @Injectable() export class UserService { constructor(private http: HttpClient) { } getAll() { return this.http.get<User[]>('/api/users'); } getById(id: number) { return this.http.get('/api/users/' + id); } create(user: User) { return this.http.post('/api/users', user); } update(user: User) { return this.http.put('/api/users/' + user.id, user); } delete(id: number) { return this.http.delete('/api/users/' + id); } }

Angular 2/5 Home Component Template

Path: /app/home/home.component.html

The home component template contains html and angular 2 template syntax for displaying a simple welcome message, a list of users and a logout link.

<div class="col-md-6 col-md-offset-3"> <h1>Hi {{currentUser.firstName}}!</h1> <p>You're logged in with Angular 2!!</p> <h3>All registered users:</h3> <ul> <li *ngFor="let user of users"> {{user.username}} ({{user.firstName}} {{user.lastName}}) - <a (click)="deleteUser(user.id)">Delete</a> </li> </ul> <p><a [routerLink]="['/login']">Logout</a></p> </div>

Angular 2/5 Home Component

Path: /app/home/home.component.ts

The home component gets the current user from local storage and all users from the user service, and makes them available to the template.

import { Component, OnInit } from '@angular/core'; import { User } from '../_models/index'; import { UserService } from '../_services/index'; @Component({ moduleId: module.id, templateUrl: 'home.component.html' }) export class HomeComponent implements OnInit { currentUser: User; users: User[] = []; constructor(private userService: UserService) { this.currentUser = JSON.parse(localStorage.getItem('currentUser')); } ngOnInit() { this.loadAllUsers(); } deleteUser(id: number) { this.userService.delete(id).subscribe(() => { this.loadAllUsers() }); } private loadAllUsers() { this.userService.getAll().subscribe(users => { this.users = users; }); } }

Angular 2/5 Login Component Template

Path: /app/login/login.component.html

The login component template contains a login form with username and password fields. It displays validation messages for invalid fields when the submit button is clicked. On submit the login() method is called as long as the form is valid.

<div class="col-md-6 col-md-offset-3"> <h2>Login</h2> <form name="form" (ngSubmit)="f.form.valid && login()" #f="ngForm" novalidate> <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !username.valid }"> <label for="username">Username</label> <input type="text" class="form-control" name="username" [(ngModel)]="model.username" #username="ngModel" required /> <div *ngIf="f.submitted && !username.valid" class="help-block">Username is required</div> </div> <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !password.valid }"> <label for="password">Password</label> <input type="password" class="form-control" name="password" [(ngModel)]="model.password" #password="ngModel" required /> <div *ngIf="f.submitted && !password.valid" class="help-block">Password is required</div> </div> <div class="form-group"> <button [disabled]="loading" class="btn btn-primary">Login</button> <img *ngIf="loading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" /> <a [routerLink]="['/register']" class="btn btn-link">Register</a> </div> </form> </div>

Angular 2/5 Login Component

Path: /app/login/login.component.ts

The login component uses the authentication service to login and logout of the application. It automatically logs the user out when it initializes (ngOnInit) so the login page can also be used to logout.

import { Component, OnInit } from '@angular/core'; import { Router, ActivatedRoute } from '@angular/router'; import { AlertService, AuthenticationService } from '../_services/index'; @Component({ moduleId: module.id, templateUrl: 'login.component.html' }) export class LoginComponent implements OnInit { model: any = {}; loading = false; returnUrl: string; constructor( private route: ActivatedRoute, private router: Router, private authenticationService: AuthenticationService, private alertService: AlertService) { } ngOnInit() { // reset login status this.authenticationService.logout(); // get return url from route parameters or default to '/' this.returnUrl = this.route.snapshot.queryParams['returnUrl'] || '/'; } login() { this.loading = true; this.authenticationService.login(this.model.username, this.model.password) .subscribe( data => { this.router.navigate([this.returnUrl]); }, error => { this.alertService.error(error); this.loading = false; }); } }

Angular 2/5 Register Component Template

Path: /app/register/register.component.html

The register component template contains a simple registration form with fields for first name, last name, username and password. It displays validation messages for invalid fields when the submit button is clicked. On submit the register() method is called if the form is valid.

<div class="col-md-6 col-md-offset-3"> <h2>Register</h2> <form name="form" (ngSubmit)="f.form.valid && register()" #f="ngForm" novalidate> <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !username.valid }"> <label for="firstName">First Name</label> <input type="text" class="form-control" name="firstName" [(ngModel)]="model.firstName" #firstName="ngModel" required /> <div *ngIf="f.submitted && !firstName.valid" class="help-block">First Name is required</div> </div> <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !username.valid }"> <label for="lastName">Last Name</label> <input type="text" class="form-control" name="lastName" [(ngModel)]="model.lastName" #lastName="ngModel" required /> <div *ngIf="f.submitted && !lastName.valid" class="help-block">Last Name is required</div> </div> <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !username.valid }"> <label for="username">Username</label> <input type="text" class="form-control" name="username" [(ngModel)]="model.username" #username="ngModel" required /> <div *ngIf="f.submitted && !username.valid" class="help-block">Username is required</div> </div> <div class="form-group" [ngClass]="{ 'has-error': f.submitted && !password.valid }"> <label for="password">Password</label> <input type="password" class="form-control" name="password" [(ngModel)]="model.password" #password="ngModel" required /> <div *ngIf="f.submitted && !password.valid" class="help-block">Password is required</div> </div> <div class="form-group"> <button [disabled]="loading" class="btn btn-primary">Register</button> <img *ngIf="loading" src="data:image/gif;base64,R0lGODlhEAAQAPIAAP///wAAAMLCwkJCQgAAAGJiYoKCgpKSkiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==" /> <a [routerLink]="['/login']" class="btn btn-link">Cancel</a> </div> </form> </div>

Angular 2/5 Register Component

Path: /app/register/register.component.ts

The register component has a single register() method that creates a new user with the user service when the register form is submitted.

import { Component } from '@angular/core'; import { Router } from '@angular/router'; import { AlertService, UserService } from '../_services/index'; @Component({ moduleId: module.id, templateUrl: 'register.component.html' }) export class RegisterComponent { model: any = {}; loading = false; constructor( private router: Router, private userService: UserService, private alertService: AlertService) { } register() { this.loading = true; this.userService.create(this.model) .subscribe( data => { // set success message and pass true paramater to persist the message after redirecting to the login page this.alertService.success('Registration successful', true); this.router.navigate(['/login']); }, error => { this.alertService.error(error); this.loading = false; }); } }

Angular 2/5 App Component Template

Path: /app/app.component.html

The app component template is the root component template of the application, it contains a router-outlet directive for displaying the contents of each view based on the current route, and an alert directive for displaying alert messages from anywhere in the system.

<!-- main app container --> <div class="jumbotron"> <div class="container"> <div class="col-sm-8 col-sm-offset-2"> <alert></alert> <router-outlet></router-outlet> </div> </div> </div>

Angular 2/5 App Component

Path: /app/app.component.ts

The app component is the root component of the application, it defines the root tag of the app as <app></app> with the selector property.

The moduleId property is set to allow a relative path to be used for the templateUrl.

import { Component } from '@angular/core'; @Component({ moduleId: module.id, selector: 'app', templateUrl: 'app.component.html' }) export class AppComponent { }

Angular 2/5 App Module

Path: /app/app.module.ts

The app module defines the root module of the application along with metadata about the module. For more info about angular 2 modules check out this page on the official docs site.

This is where the fake backend provider is added to the application, to switch to a real backend simply remove the providers located under the comment "// providers used to create fake backend".

import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { FormsModule } from '@angular/forms'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; // used to create fake backend import { fakeBackendProvider } from './_helpers/index'; import { AppComponent } from './app.component'; import { routing } from './app.routing'; import { AlertComponent } from './_directives/index'; import { AuthGuard } from './_guards/index'; import { JwtInterceptor } from './_helpers/index'; import { AlertService, AuthenticationService, UserService } from './_services/index'; import { HomeComponent } from './home/index'; import { LoginComponent } from './login/index'; import { RegisterComponent } from './register/index'; @NgModule({ imports: [ BrowserModule, FormsModule, HttpClientModule, routing ], declarations: [ AppComponent, AlertComponent, HomeComponent, LoginComponent, RegisterComponent ], providers: [ AuthGuard, AlertService, AuthenticationService, UserService, { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }, // provider used to create fake backend fakeBackendProvider ], bootstrap: [AppComponent] }) export class AppModule { }

Angular 2/5 App Routing

Path: /app/app.routing.ts

The app routing file defines the routes of the application, each route contains a path and associated component. The home route is secured by passing the AuthGuard to the canActivate property of the route.

import { Routes, RouterModule } from '@angular/router'; import { HomeComponent } from './home/index'; import { LoginComponent } from './login/index'; import { RegisterComponent } from './register/index'; import { AuthGuard } from './_guards/index'; const appRoutes: Routes = [ { path: '', component: HomeComponent, canActivate: [AuthGuard] }, { path: 'login', component: LoginComponent }, { path: 'register', component: RegisterComponent }, // otherwise redirect to home { path: '**', redirectTo: '' } ]; export const routing = RouterModule.forRoot(appRoutes);

Angular 2/5 Main (Bootstrap) File

Path: /app/main.ts

The main file is the entry point used by angular to launch and bootstrap the application.