diff --git a/src/app/app.component.html b/src/app/app.component.html
index 532d4b3..16768ec 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,14 +1,9 @@
-
-
+
+
Welcome to {{title}}!
-
+
\ No newline at end of file
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index 341343b..7ae2166 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -7,6 +7,7 @@ import { Component } from '@angular/core';
styleUrls: ['./app.component.css']
})
export class AppComponent {
+ title = "Angular 2";
task = {
title: 'Review Applications',
assignee: null
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 92b46e5..f12a77d 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -1,8 +1,12 @@
+import { ErrorHandler } from '@angular/core';
+import { AppErrorHandler } from './common/app-error-handler';
+import { PostService } from './services/post.service';
import { SummaryPipe } from './summary.pipe';
import { CoursesService } from './course.service';
import { CoursesComponent } from './courses.component';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
+import { HttpModule } from '@angular/http';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { CourseComponent } from './course/course.component';
@@ -11,6 +15,9 @@ import { PanelComponent } from './panel/panel.component';
import { InputFormatDirective } from './input-format.directive';
import { ContactFormComponent } from './contact-form/contact-form.component';
import { SignupFormComponent } from './signup-form/signup-form.component';
+import { ChangePasswordFormComponent } from "./assignments/change-password-form/change-password-form.component";
+import { PostsComponent } from './posts/posts.component';
+
@NgModule({
declarations: [
@@ -22,15 +29,21 @@ import { SignupFormComponent } from './signup-form/signup-form.component';
PanelComponent,
InputFormatDirective,
ContactFormComponent,
- SignupFormComponent
+ SignupFormComponent,
+ ChangePasswordFormComponent,
+ PostsComponent
],
imports: [
BrowserModule,
FormsModule,
- ReactiveFormsModule
+ ReactiveFormsModule,
+ HttpModule
],
providers: [
- CoursesService
+ CoursesService,
+ PostService,
+ AppErrorHandler,
+ { provide: ErrorHandler, useClass: AppErrorHandler}
],
bootstrap: [AppComponent]
})
diff --git a/src/app/assignments/change-password-form/change-password-form.component.css b/src/app/assignments/change-password-form/change-password-form.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/assignments/change-password-form/change-password-form.component.html b/src/app/assignments/change-password-form/change-password-form.component.html
new file mode 100644
index 0000000..0fabba2
--- /dev/null
+++ b/src/app/assignments/change-password-form/change-password-form.component.html
@@ -0,0 +1,36 @@
+
\ No newline at end of file
diff --git a/src/app/assignments/change-password-form/change-password-form.component.spec.ts b/src/app/assignments/change-password-form/change-password-form.component.spec.ts
new file mode 100644
index 0000000..5890b77
--- /dev/null
+++ b/src/app/assignments/change-password-form/change-password-form.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ChangePasswordFormComponent } from './change-password-form.component';
+
+describe('ChangePasswordFormComponent', () => {
+ let component: ChangePasswordFormComponent;
+ let fixture: ComponentFixture
;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ChangePasswordFormComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ChangePasswordFormComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/assignments/change-password-form/change-password-form.component.ts b/src/app/assignments/change-password-form/change-password-form.component.ts
new file mode 100644
index 0000000..bd8d5cb
--- /dev/null
+++ b/src/app/assignments/change-password-form/change-password-form.component.ts
@@ -0,0 +1,35 @@
+import { PasswordValidators } from './password.validators';
+import { FormBuilder, Validators, FormGroup } from '@angular/forms';
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+ selector: 'change-password-form',
+ templateUrl: './change-password-form.component.html',
+ styleUrls: ['./change-password-form.component.css']
+})
+export class ChangePasswordFormComponent {
+ form: FormGroup;
+ constructor(private fb: FormBuilder) {
+ this.form = fb.group({
+ oldPassword: ['',
+ Validators.required,
+ PasswordValidators.validOldPassword],
+
+ newPassword: ['', Validators.required],
+ confirmPassword: ['', Validators.required]
+ }, {
+ validator: PasswordValidators.passwordShouldMatch
+ });
+ }
+
+ get newPassword(){
+ return this.form.get('newPassword');
+ }
+ get oldPassword(){
+ return this.form.get('oldPassword');
+ }
+ get confirmPassword(){
+ return this.form.get('confirmPassword');
+ }
+
+}
diff --git a/src/app/assignments/change-password-form/password.validators.ts b/src/app/assignments/change-password-form/password.validators.ts
new file mode 100644
index 0000000..6f7b202
--- /dev/null
+++ b/src/app/assignments/change-password-form/password.validators.ts
@@ -0,0 +1,24 @@
+import { ValidationErrors, AbstractControl } from '@angular/forms';
+export class PasswordValidators {
+
+ static validOldPassword(control: AbstractControl) {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ if (control.value !== '1212') {
+ resolve({ invalidOldPassword: true })
+ }
+ else
+ resolve(null);
+ }, 2000);
+ });
+ }
+
+ static passwordShouldMatch(control: AbstractControl) {
+ let newPassword = control.get('newPassword');
+ let confirmPassword = control.get('confirmPassword');
+ if (newPassword.value !== confirmPassword.value)
+ return { passwordShouldMatch: true };
+ else
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/src/app/common/app-error-handler.ts b/src/app/common/app-error-handler.ts
new file mode 100644
index 0000000..ec8e833
--- /dev/null
+++ b/src/app/common/app-error-handler.ts
@@ -0,0 +1,9 @@
+import { ErrorHandler } from "@angular/core";
+
+export class AppErrorHandler implements ErrorHandler{
+ handleError(error: any): void {
+ alert('An expected error occurred.');
+ console.log(error);
+ }
+
+}
\ No newline at end of file
diff --git a/src/app/common/app-error.ts b/src/app/common/app-error.ts
new file mode 100644
index 0000000..c95295f
--- /dev/null
+++ b/src/app/common/app-error.ts
@@ -0,0 +1,5 @@
+export class AppError{
+ constructor(public originalError?: any){
+
+ }
+}
\ No newline at end of file
diff --git a/src/app/common/bad-request-error.ts b/src/app/common/bad-request-error.ts
new file mode 100644
index 0000000..57eb17f
--- /dev/null
+++ b/src/app/common/bad-request-error.ts
@@ -0,0 +1,4 @@
+import { AppError } from './app-error';
+export class BadRequestError extends AppError {
+
+}
\ No newline at end of file
diff --git a/src/app/common/not-found-error.ts b/src/app/common/not-found-error.ts
new file mode 100644
index 0000000..729b423
--- /dev/null
+++ b/src/app/common/not-found-error.ts
@@ -0,0 +1,4 @@
+import { AppError } from './app-error';
+export class NotFoundError extends AppError{
+
+}
\ No newline at end of file
diff --git a/src/app/course/course.component.html b/src/app/course/course.component.html
index e8f7228..10b1cb7 100644
--- a/src/app/course/course.component.html
+++ b/src/app/course/course.component.html
@@ -1,8 +1,31 @@
-
\ No newline at end of file
diff --git a/src/app/course/course.component.ts b/src/app/course/course.component.ts
index 230e398..61fb1fb 100644
--- a/src/app/course/course.component.ts
+++ b/src/app/course/course.component.ts
@@ -1,4 +1,5 @@
-import { FormGroup, FormArray, FormControl } from '@angular/forms';
+import { UsernameValidators } from './../signup-form/username.validators';
+import { FormGroup, FormArray, FormBuilder, Validators } from '@angular/forms';
import { Component, OnInit } from '@angular/core';
@Component({
@@ -7,18 +8,23 @@ import { Component, OnInit } from '@angular/core';
styleUrls: ['./course.component.css']
})
export class CourseComponent {
- form = new FormGroup({
- topics: new FormArray([])
- });
- addTopic(topic: HTMLInputElement) {
- this.topics.push(new FormControl(topic.value));
- topic.value = "";
+ form: FormGroup;
+ constructor(fb: FormBuilder) {
+ this.form = fb.group({
+ name: ['', [Validators.required, Validators.minLength(3)], UsernameValidators.shouldBeUnique],
+ contact: fb.group({
+ email: ['', [Validators.required, Validators.pattern('^[a-z]+[a-z0-9._]+@[a-z]+\.[a-z.]{2,5}$')]],
+ phone: ['', [Validators.required, Validators.pattern('^[0-9]*$')]]
+ }),
+ topics: fb.array([])
+ });
}
- removeTopic(topic: FormControl){
- let index = this.topics.controls.indexOf(topic);
- this.topics.removeAt(index);
+
+ addTopic(name) {
+ this.form.value.topics.push(name.value);
}
- get topics(){
- return this.form.get('topics') as FormArray;
+ removeTopic(topic) {
+ let index = this.form.value.topics.indexOf(topic);
+ this.form.value.topics.splice(index, 1);
}
}
diff --git a/src/app/posts/posts.component.css b/src/app/posts/posts.component.css
new file mode 100644
index 0000000..e69de29
diff --git a/src/app/posts/posts.component.html b/src/app/posts/posts.component.html
new file mode 100644
index 0000000..06ca2b9
--- /dev/null
+++ b/src/app/posts/posts.component.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+ | Id |
+ Title |
+ # |
+
+
+
+
+ | {{ p.id }} |
+ {{ p.title }} |
+
+
+
+ |
+
+
+
+
\ No newline at end of file
diff --git a/src/app/posts/posts.component.spec.ts b/src/app/posts/posts.component.spec.ts
new file mode 100644
index 0000000..ff74bdb
--- /dev/null
+++ b/src/app/posts/posts.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PostsComponent } from './posts.component';
+
+describe('PostsComponent', () => {
+ let component: PostsComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ PostsComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(PostsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/posts/posts.component.ts b/src/app/posts/posts.component.ts
new file mode 100644
index 0000000..00c9cb5
--- /dev/null
+++ b/src/app/posts/posts.component.ts
@@ -0,0 +1,61 @@
+import { AppError } from './../common/app-error';
+import { BadRequestError } from './../common/bad-request-error';
+import { NotFoundError } from './../common/not-found-error';
+import { PostService } from './../services/post.service';
+import { Component, OnInit } from '@angular/core';
+import { Http } from "@angular/http";
+
+@Component({
+ selector: 'posts',
+ templateUrl: './posts.component.html',
+ styleUrls: ['./posts.component.css']
+})
+export class PostsComponent implements OnInit {
+ ngOnInit(): void {
+ this.service.getAll().subscribe(posts => this.posts = posts);
+ }
+
+ posts: any[];
+
+
+ constructor(private service: PostService) {
+
+ }
+
+ createPost(input: HTMLInputElement) {
+ let post: any = { title: input.value };
+ input.value = '';
+ this.posts.splice(0, 0, post);
+
+ this.service.create(post).subscribe(posts => {
+ post['id'] = posts.id;
+ }, (error: AppError) => {
+ this.posts.splice(0, 1);
+ if (error instanceof BadRequestError) {
+ // this.form.setErrors(error.originalError);
+ }
+ else
+ throw error;
+ });
+ }
+
+ updatePost(post: any) {
+ this.service.update(post)
+ .subscribe(updatedPost => {
+ console.log(updatedPost);
+ });
+ }
+
+ deletePost(post: any) {
+ let index = this.posts.indexOf(post);
+ this.posts.splice(index, 1);
+ this.service.delete(post.id)
+ .subscribe(null, (error: AppError) => {
+ this.posts.splice(index, 0, post);
+ if (error instanceof NotFoundError)
+ alert('This post has already been deleted.');
+ else throw error;
+ });
+ }
+
+}
diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts
new file mode 100644
index 0000000..c63308c
--- /dev/null
+++ b/src/app/services/data.service.ts
@@ -0,0 +1,47 @@
+import { BadRequestError } from './../common/bad-request-error';
+import { NotFoundError } from './../common/not-found-error';
+import { AppError } from './../common/app-error';
+import { Http } from '@angular/http';
+import { Injectable } from '@angular/core';
+import "rxjs/add/operator/catch";
+import "rxjs/add/operator/map";
+import "rxjs/add/observable/throw";
+import { Observable } from "rxjs/Observable";
+
+@Injectable()
+export class DataService {
+
+ constructor(private url: string, private http: Http) {
+
+ }
+ getAll() {
+ return this.http.get(this.url)
+ .map(response => response.json())
+ .catch(this.handleError);
+ }
+
+ create(resource) {
+ //return Observable.throw(new AppError());
+ return this.http.post(this.url, JSON.stringify(resource))
+ .map(response => response.json())
+ .catch(this.handleError);
+ }
+ update(resource) {
+ return this.http.patch(this.url + '/' + resource.id, JSON.stringify({ isRead: true }))
+ .catch(this.handleError);
+ }
+ delete(id) {
+ return Observable.throw(new AppError());
+ // return this.http.delete(this.url + '/' + id)
+ // .catch(this.handleError);
+ }
+ private handleError(error: Response) {
+ if (error.status === 400)
+ return Observable.throw(new BadRequestError(error.json()));
+
+ if (error.status === 404)
+ return Observable.throw(new NotFoundError());
+ else
+ return Observable.throw(new AppError(error));
+ }
+}
diff --git a/src/app/services/post.service.spec.ts b/src/app/services/post.service.spec.ts
new file mode 100644
index 0000000..b19a88e
--- /dev/null
+++ b/src/app/services/post.service.spec.ts
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { PostService } from './post.service';
+
+describe('PostService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [PostService]
+ });
+ });
+
+ it('should be created', inject([PostService], (service: PostService) => {
+ expect(service).toBeTruthy();
+ }));
+});
diff --git a/src/app/services/post.service.ts b/src/app/services/post.service.ts
new file mode 100644
index 0000000..73c98b4
--- /dev/null
+++ b/src/app/services/post.service.ts
@@ -0,0 +1,11 @@
+import { Http } from '@angular/http';
+import { DataService } from './data.service';
+import { Injectable } from '@angular/core';
+
+@Injectable()
+export class PostService extends DataService {
+
+ constructor(http: Http) {
+ super('http://jsonplaceholder.typicode.com/posts', http);
+ }
+}
diff --git a/src/styles.css b/src/styles.css
index 9df75fe..2952200 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -1,6 +1,11 @@
/* You can add global styles to this file, and also import other style files */
@import "~bootstrap/dist/css/bootstrap.css";
+#main-wrapper {
+ margin: 0 auto;
+ width: 50%;
+}
+
.form-control.ng-invalid.ng-touched {
border: 1px solid #a94442;
}
\ No newline at end of file