From 6fb59b9da52129d7c49684130776d0795b7164be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Thu, 31 Aug 2017 18:42:53 +0700 Subject: [PATCH 1/9] working with form builder --- src/app/app.component.html | 2 +- src/app/course/course.component.html | 37 ++++++++++++++++++++++------ src/app/course/course.component.ts | 30 +++++++++++++--------- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index 532d4b3..f0e019a 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -7,7 +7,7 @@

- +
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 @@ -
- -
    -
  • - {{ topic.value }} -
  • -
+ +
+ + + +
Name is is required
+
Name should be minumum 3 characters.
+
Name is already taken.
+ +
    +
  • + {{ topic }} +
  • +
+
+
+
+ + +
Email is is required
+
Email format is not valid
+
+
+ + +
Phone is is required
+
Phone format is not valid
+
+
+
\ 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); } } From a0cb4c339d8b1c1faf7b38f70acf3f60428f30da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Thu, 31 Aug 2017 18:49:45 +0700 Subject: [PATCH 2/9] improve looks and feels for app. --- src/app/app.component.html | 12 ++++-------- src/app/app.component.ts | 1 + src/styles.css | 5 +++++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/app/app.component.html b/src/app/app.component.html index f0e019a..6f591d4 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,14 +1,10 @@ -
-

+
+

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/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 From 9ddab72d150ae44b533419565adf124a8b5a38ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Thu, 31 Aug 2017 20:54:15 +0700 Subject: [PATCH 3/9] complete assignment change password. --- src/app/app.component.html | 3 +- src/app/app.module.ts | 5 ++- .../change-password-form.component.css | 0 .../change-password-form.component.html | 36 +++++++++++++++++++ .../change-password-form.component.spec.ts | 25 +++++++++++++ .../change-password-form.component.ts | 35 ++++++++++++++++++ .../password.validators.ts | 24 +++++++++++++ 7 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 src/app/assignments/change-password-form/change-password-form.component.css create mode 100644 src/app/assignments/change-password-form/change-password-form.component.html create mode 100644 src/app/assignments/change-password-form/change-password-form.component.spec.ts create mode 100644 src/app/assignments/change-password-form/change-password-form.component.ts create mode 100644 src/app/assignments/change-password-form/password.validators.ts diff --git a/src/app/app.component.html b/src/app/app.component.html index 6f591d4..1cc8bc7 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -4,7 +4,6 @@

Welcome to {{title}}!

- - +

\ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 92b46e5..3a4fc3a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -11,6 +11,8 @@ 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"; + @NgModule({ declarations: [ @@ -22,7 +24,8 @@ import { SignupFormComponent } from './signup-form/signup-form.component'; PanelComponent, InputFormatDirective, ContactFormComponent, - SignupFormComponent + SignupFormComponent, + ChangePasswordFormComponent ], imports: [ BrowserModule, 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 @@ +
+
+ + +
+
Old Password is required
+
Old Password is invalid.
+
+
+ Checking valid password... +
+
+
+ + +
+
New password is required
+
+ +
+ +
+ + +
+
+ Confirm password is required +
+
+
+ Password do not match. +
+
+ + +
\ 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 From ec5bd26e28af875697e2f6d4bb155ef9d380e5d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Thu, 31 Aug 2017 21:57:00 +0700 Subject: [PATCH 4/9] crud using http service. --- src/app/app.component.html | 2 +- src/app/app.module.ts | 8 +++-- src/app/posts/posts.component.css | 0 src/app/posts/posts.component.html | 22 +++++++++++++ src/app/posts/posts.component.spec.ts | 25 ++++++++++++++ src/app/posts/posts.component.ts | 47 +++++++++++++++++++++++++++ 6 files changed, 101 insertions(+), 3 deletions(-) create mode 100644 src/app/posts/posts.component.css create mode 100644 src/app/posts/posts.component.html create mode 100644 src/app/posts/posts.component.spec.ts create mode 100644 src/app/posts/posts.component.ts diff --git a/src/app/app.component.html b/src/app/app.component.html index 1cc8bc7..16768ec 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -4,6 +4,6 @@

Welcome to {{title}}!

- + \ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 3a4fc3a..ff8d554 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -3,6 +3,7 @@ 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'; @@ -12,6 +13,7 @@ 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({ @@ -25,12 +27,14 @@ import { ChangePasswordFormComponent } from "./assignments/change-password-form/ InputFormatDirective, ContactFormComponent, SignupFormComponent, - ChangePasswordFormComponent + ChangePasswordFormComponent, + PostsComponent ], imports: [ BrowserModule, FormsModule, - ReactiveFormsModule + ReactiveFormsModule, + HttpModule ], providers: [ CoursesService 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 @@ + +
+ + + + + + + + + + + + + + + +
IdTitle#
{{ 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..4aa43c7 --- /dev/null +++ b/src/app/posts/posts.component.ts @@ -0,0 +1,47 @@ +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 { + + posts: any[]; + private url = "http://jsonplaceholder.typicode.com/posts"; + + constructor(private http: Http) { + http.get(this.url) + .subscribe(response => { + this.posts = response.json(); + }); + } + + createPost(input: HTMLInputElement) { + let post: any = { + title: input.value + } + input.value = ''; + this.http.post(this.url, JSON.stringify(post)).subscribe(respone => { + this.posts.splice(0, 0, post); + post['id'] = respone.json().id; + }); + } + + updatePost(post: any) { + this.http.patch(this.url + '/' + post.id, JSON.stringify({ isRead: true })) + .subscribe(respone => { + console.log(respone.json()); + }); + } + + deletePost(post: any) { + this.http.delete(this.url + '/' + post.id) + .subscribe(respone => { + let index = this.posts.indexOf(post); + this.posts.splice(index, 1); + }); + } + +} From f9bc455b9d222ec8d697f4ae681cb7b4263644ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Thu, 31 Aug 2017 22:33:48 +0700 Subject: [PATCH 5/9] extracting post services --- src/app/app.module.ts | 4 +++- src/app/posts/posts.component.ts | 24 ++++++++++++++---------- src/app/services/post.service.spec.ts | 15 +++++++++++++++ src/app/services/post.service.ts | 23 +++++++++++++++++++++++ 4 files changed, 55 insertions(+), 11 deletions(-) create mode 100644 src/app/services/post.service.spec.ts create mode 100644 src/app/services/post.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ff8d554..1b2a381 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,3 +1,4 @@ +import { PostService } from './services/post.service'; import { SummaryPipe } from './summary.pipe'; import { CoursesService } from './course.service'; import { CoursesComponent } from './courses.component'; @@ -37,7 +38,8 @@ import { PostsComponent } from './posts/posts.component'; HttpModule ], providers: [ - CoursesService + CoursesService, + PostService ], bootstrap: [AppComponent] }) diff --git a/src/app/posts/posts.component.ts b/src/app/posts/posts.component.ts index 4aa43c7..3964a10 100644 --- a/src/app/posts/posts.component.ts +++ b/src/app/posts/posts.component.ts @@ -1,3 +1,4 @@ +import { PostService } from './../services/post.service'; import { Component, OnInit } from '@angular/core'; import { Http } from "@angular/http"; @@ -6,16 +7,19 @@ import { Http } from "@angular/http"; templateUrl: './posts.component.html', styleUrls: ['./posts.component.css'] }) -export class PostsComponent { +export class PostsComponent implements OnInit{ + ngOnInit(): void { + this.service.getPosts() + .subscribe(response => { + this.posts = response.json(); + }); + } posts: any[]; - private url = "http://jsonplaceholder.typicode.com/posts"; + - constructor(private http: Http) { - http.get(this.url) - .subscribe(response => { - this.posts = response.json(); - }); + constructor(private service: PostService) { + } createPost(input: HTMLInputElement) { @@ -23,21 +27,21 @@ export class PostsComponent { title: input.value } input.value = ''; - this.http.post(this.url, JSON.stringify(post)).subscribe(respone => { + this.service.createPost(post).subscribe(respone => { this.posts.splice(0, 0, post); post['id'] = respone.json().id; }); } updatePost(post: any) { - this.http.patch(this.url + '/' + post.id, JSON.stringify({ isRead: true })) + this.service.updatePost(post) .subscribe(respone => { console.log(respone.json()); }); } deletePost(post: any) { - this.http.delete(this.url + '/' + post.id) + this.service.deletePost(post.id) .subscribe(respone => { let index = this.posts.indexOf(post); this.posts.splice(index, 1); 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..361121b --- /dev/null +++ b/src/app/services/post.service.ts @@ -0,0 +1,23 @@ +import { Http } from '@angular/http'; +import { Injectable } from '@angular/core'; + +@Injectable() +export class PostService { + private url = "http://jsonplaceholder.typicode.com/posts"; + constructor(private http: Http) { + + } + getPosts(){ + return this.http.get(this.url) + } + + createPost(post){ + return this.http.post(this.url, JSON.stringify(post)); + } + updatePost(post){ + return this.http.patch(this.url + '/' + post.id, JSON.stringify({ isRead: true })); + } + deletePost(id){ + return this.http.delete(this.url + '/'+ id); + } +} From ff0d9f83ef22e148766b7559e33622a38ec0d437 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Thu, 31 Aug 2017 23:50:33 +0700 Subject: [PATCH 6/9] working with error handler. --- src/app/app.module.ts | 6 ++++- src/app/common/app-error-handler.ts | 9 +++++++ src/app/common/app-error.ts | 5 ++++ src/app/common/bad-request-error.ts | 4 +++ src/app/common/not-found-error.ts | 4 +++ src/app/posts/posts.component.ts | 25 ++++++++++++++----- src/app/services/post.service.ts | 38 +++++++++++++++++++++-------- 7 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 src/app/common/app-error-handler.ts create mode 100644 src/app/common/app-error.ts create mode 100644 src/app/common/bad-request-error.ts create mode 100644 src/app/common/not-found-error.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 1b2a381..f12a77d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,3 +1,5 @@ +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'; @@ -39,7 +41,9 @@ import { PostsComponent } from './posts/posts.component'; ], providers: [ CoursesService, - PostService + PostService, + AppErrorHandler, + { provide: ErrorHandler, useClass: AppErrorHandler} ], bootstrap: [AppComponent] }) 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/posts/posts.component.ts b/src/app/posts/posts.component.ts index 3964a10..e6b27d3 100644 --- a/src/app/posts/posts.component.ts +++ b/src/app/posts/posts.component.ts @@ -1,3 +1,6 @@ +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"; @@ -7,19 +10,19 @@ import { Http } from "@angular/http"; templateUrl: './posts.component.html', styleUrls: ['./posts.component.css'] }) -export class PostsComponent implements OnInit{ +export class PostsComponent implements OnInit { ngOnInit(): void { this.service.getPosts() - .subscribe(response => { - this.posts = response.json(); - }); + .subscribe(response => { + this.posts = response.json(); + }); } posts: any[]; - + constructor(private service: PostService) { - + } createPost(input: HTMLInputElement) { @@ -30,6 +33,12 @@ export class PostsComponent implements OnInit{ this.service.createPost(post).subscribe(respone => { this.posts.splice(0, 0, post); post['id'] = respone.json().id; + }, (error: AppError) => { + if (error instanceof BadRequestError) { + // this.form.setErrors(error.originalError); + } + else + throw error; }); } @@ -45,6 +54,10 @@ export class PostsComponent implements OnInit{ .subscribe(respone => { let index = this.posts.indexOf(post); this.posts.splice(index, 1); + }, (error: AppError) => { + if (error instanceof NotFoundError) + alert('This post has already been deleted.'); + else throw error; }); } diff --git a/src/app/services/post.service.ts b/src/app/services/post.service.ts index 361121b..ef51c52 100644 --- a/src/app/services/post.service.ts +++ b/src/app/services/post.service.ts @@ -1,23 +1,41 @@ +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/observable/throw"; +import { Observable } from "rxjs/Observable"; @Injectable() export class PostService { private url = "http://jsonplaceholder.typicode.com/posts"; constructor(private http: Http) { - + + } + getPosts() { + return this.http.get(this.url).catch(this.handleError); } - getPosts(){ - return this.http.get(this.url) + + createPost(post) { + return this.http.post(this.url, JSON.stringify(post)) + .catch(this.handleError); } - - createPost(post){ - return this.http.post(this.url, JSON.stringify(post)); + updatePost(post) { + return this.http.patch(this.url + '/' + post.id, JSON.stringify({ isRead: true })) + .catch(this.handleError); } - updatePost(post){ - return this.http.patch(this.url + '/' + post.id, JSON.stringify({ isRead: true })); + deletePost(id) { + return this.http.delete(this.url + '/' + id) + .catch(this.handleError); } - deletePost(id){ - return this.http.delete(this.url + '/'+ id); + 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)); } } From fee806d0fe8636fc3adcce99a092aab8ccbb54c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Fri, 1 Sep 2017 00:01:41 +0700 Subject: [PATCH 7/9] extracting reusable service. --- src/app/posts/posts.component.ts | 8 +++---- src/app/services/data.service.ts | 41 ++++++++++++++++++++++++++++++++ src/app/services/post.service.ts | 40 ++++--------------------------- 3 files changed, 50 insertions(+), 39 deletions(-) create mode 100644 src/app/services/data.service.ts diff --git a/src/app/posts/posts.component.ts b/src/app/posts/posts.component.ts index e6b27d3..a4d5f2f 100644 --- a/src/app/posts/posts.component.ts +++ b/src/app/posts/posts.component.ts @@ -12,7 +12,7 @@ import { Http } from "@angular/http"; }) export class PostsComponent implements OnInit { ngOnInit(): void { - this.service.getPosts() + this.service.getAll() .subscribe(response => { this.posts = response.json(); }); @@ -30,7 +30,7 @@ export class PostsComponent implements OnInit { title: input.value } input.value = ''; - this.service.createPost(post).subscribe(respone => { + this.service.create(post).subscribe(respone => { this.posts.splice(0, 0, post); post['id'] = respone.json().id; }, (error: AppError) => { @@ -43,14 +43,14 @@ export class PostsComponent implements OnInit { } updatePost(post: any) { - this.service.updatePost(post) + this.service.update(post) .subscribe(respone => { console.log(respone.json()); }); } deletePost(post: any) { - this.service.deletePost(post.id) + this.service.delete(post.id) .subscribe(respone => { let index = this.posts.indexOf(post); this.posts.splice(index, 1); diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts new file mode 100644 index 0000000..0665aef --- /dev/null +++ b/src/app/services/data.service.ts @@ -0,0 +1,41 @@ +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/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).catch(this.handleError); + } + + create(resource) { + return this.http.post(this.url, JSON.stringify(resource)) + .catch(this.handleError); + } + update(resource) { + return this.http.patch(this.url + '/' + resource.id, JSON.stringify({ isRead: true })) + .catch(this.handleError); + } + delete(id) { + 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.ts b/src/app/services/post.service.ts index ef51c52..73c98b4 100644 --- a/src/app/services/post.service.ts +++ b/src/app/services/post.service.ts @@ -1,41 +1,11 @@ -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 { DataService } from './data.service'; import { Injectable } from '@angular/core'; -import "rxjs/add/operator/catch"; -import "rxjs/add/observable/throw"; -import { Observable } from "rxjs/Observable"; @Injectable() -export class PostService { - private url = "http://jsonplaceholder.typicode.com/posts"; - constructor(private http: Http) { - - } - getPosts() { - return this.http.get(this.url).catch(this.handleError); - } - - createPost(post) { - return this.http.post(this.url, JSON.stringify(post)) - .catch(this.handleError); - } - updatePost(post) { - return this.http.patch(this.url + '/' + post.id, JSON.stringify({ isRead: true })) - .catch(this.handleError); - } - deletePost(id) { - 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)); +export class PostService extends DataService { + + constructor(http: Http) { + super('http://jsonplaceholder.typicode.com/posts', http); } } From 045e7ca16c694182b2e238e9a286fc07673fd01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Fri, 1 Sep 2017 00:10:34 +0700 Subject: [PATCH 8/9] working with map operator. --- src/app/posts/posts.component.ts | 15 ++++++--------- src/app/services/data.service.ts | 8 ++++++-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/app/posts/posts.component.ts b/src/app/posts/posts.component.ts index a4d5f2f..4365ef7 100644 --- a/src/app/posts/posts.component.ts +++ b/src/app/posts/posts.component.ts @@ -12,10 +12,7 @@ import { Http } from "@angular/http"; }) export class PostsComponent implements OnInit { ngOnInit(): void { - this.service.getAll() - .subscribe(response => { - this.posts = response.json(); - }); + this.service.getAll().subscribe(posts => this.posts = posts); } posts: any[]; @@ -30,9 +27,9 @@ export class PostsComponent implements OnInit { title: input.value } input.value = ''; - this.service.create(post).subscribe(respone => { + this.service.create(post).subscribe(posts => { this.posts.splice(0, 0, post); - post['id'] = respone.json().id; + post['id'] = posts.id; }, (error: AppError) => { if (error instanceof BadRequestError) { // this.form.setErrors(error.originalError); @@ -44,14 +41,14 @@ export class PostsComponent implements OnInit { updatePost(post: any) { this.service.update(post) - .subscribe(respone => { - console.log(respone.json()); + .subscribe(updatedPost => { + console.log(updatedPost); }); } deletePost(post: any) { this.service.delete(post.id) - .subscribe(respone => { + .subscribe(() => { let index = this.posts.indexOf(post); this.posts.splice(index, 1); }, (error: AppError) => { diff --git a/src/app/services/data.service.ts b/src/app/services/data.service.ts index 0665aef..00c3736 100644 --- a/src/app/services/data.service.ts +++ b/src/app/services/data.service.ts @@ -4,21 +4,25 @@ 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).catch(this.handleError); + return this.http.get(this.url) + .map(response => response.json()) + .catch(this.handleError); } create(resource) { return this.http.post(this.url, JSON.stringify(resource)) + .map(response => response.json()) .catch(this.handleError); } update(resource) { From 53d2ecc948c0b045ddc9bc47e187867db3494056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A2m=20Davies?= Date: Fri, 1 Sep 2017 17:38:26 +0700 Subject: [PATCH 9/9] optimistic update --- src/app/posts/posts.component.ts | 18 +++++++++--------- src/app/services/data.service.ts | 6 ++++-- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/app/posts/posts.component.ts b/src/app/posts/posts.component.ts index 4365ef7..00c9cb5 100644 --- a/src/app/posts/posts.component.ts +++ b/src/app/posts/posts.component.ts @@ -23,15 +23,15 @@ export class PostsComponent implements OnInit { } createPost(input: HTMLInputElement) { - let post: any = { - title: input.value - } + let post: any = { title: input.value }; input.value = ''; + this.posts.splice(0, 0, post); + this.service.create(post).subscribe(posts => { - this.posts.splice(0, 0, post); post['id'] = posts.id; }, (error: AppError) => { - if (error instanceof BadRequestError) { + this.posts.splice(0, 1); + if (error instanceof BadRequestError) { // this.form.setErrors(error.originalError); } else @@ -47,11 +47,11 @@ export class PostsComponent implements OnInit { } deletePost(post: any) { + let index = this.posts.indexOf(post); + this.posts.splice(index, 1); this.service.delete(post.id) - .subscribe(() => { - let index = this.posts.indexOf(post); - this.posts.splice(index, 1); - }, (error: AppError) => { + .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 index 00c3736..c63308c 100644 --- a/src/app/services/data.service.ts +++ b/src/app/services/data.service.ts @@ -21,6 +21,7 @@ export class DataService { } create(resource) { + //return Observable.throw(new AppError()); return this.http.post(this.url, JSON.stringify(resource)) .map(response => response.json()) .catch(this.handleError); @@ -30,8 +31,9 @@ export class DataService { .catch(this.handleError); } delete(id) { - return this.http.delete(this.url + '/' + id) - .catch(this.handleError); + return Observable.throw(new AppError()); + // return this.http.delete(this.url + '/' + id) + // .catch(this.handleError); } private handleError(error: Response) { if (error.status === 400)