diff --git a/README.md b/README.md index 995c7e0..27c4042 100644 --- a/README.md +++ b/README.md @@ -86,3 +86,15 @@ The application is a simple contacts application where you can search, create or - Remove `ng-app` from `index.html` file - Add polyfills, `NgModule` and hybrid bootstrap code to `app.main.ts` +### Step 7 - Services to Angular + +- Added `rxjs-operators.ts` and imported it into main.ts, this is where we will add the rxjs operators we need in our application. +- Add `HttpModule` to `NgModule` so we can use `Http` in our resource. +- Convert `contact.resource` to Angular service, no need to downgrade since it's only being used in an Angular entity but we do need to add it to the `NgModule`. +- Convert `contact.service` to an Angular service. + - It needs to be downgraded so we can use it in an AngularJS entity. + - It depends on a 3rd party component called Toaster which only works in AngularJS, so we upgrade Toaster to use it in Angular via `ajs-upgraded-providers.ts` + - We inject our upgraded Toaster using the `@Inject` annotation. + + + diff --git a/package.json b/package.json index 0aabbd2..e16a6f9 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "core-js": "^2.4.1", "rxjs": "^5.1.0", "zone.js": "^0.8.4", + "reflect-metadata": "^0.1.10", "angular": "^1.6.2", "angular-animate": "^1.6.2", diff --git a/src/app/ajs-upgraded-providers.ts b/src/app/ajs-upgraded-providers.ts new file mode 100644 index 0000000..0fe1c16 --- /dev/null +++ b/src/app/ajs-upgraded-providers.ts @@ -0,0 +1,11 @@ +import {OpaqueToken} from "@angular/core"; +export const Toaster = new OpaqueToken("Toaster"); + +export function toasterServiceFactory(i: any) { + return i.get('toaster'); +} +export const toasterServiceProvider = { + provide: Toaster, + useFactory: toasterServiceFactory, + deps: ['$injector'] +}; \ No newline at end of file diff --git a/src/app/main.ts b/src/app/main.ts index b52417c..3aa4ef9 100644 --- a/src/app/main.ts +++ b/src/app/main.ts @@ -9,22 +9,37 @@ import 'angular-strap'; import 'angularjs-toaster'; import 'angular-ui-router'; +import 'reflect-metadata'; + import './app.main'; import './services'; import './filters'; import './components'; import './app.routes'; import './polyfills.ts'; +import './rxjs-operators.ts'; import {NgModule} from '@angular/core'; import {BrowserModule} from '@angular/platform-browser'; import {UpgradeModule} from '@angular/upgrade/static'; +import {HttpModule} from '@angular/http'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; + +import {toasterServiceProvider} from "./ajs-upgraded-providers" +import {Contact} from "./services/contact.resource"; +import {ContactService} from "./services/contact.service"; + @NgModule({ imports: [ BrowserModule, - UpgradeModule + UpgradeModule, + HttpModule + ], + providers: [ + Contact, + ContactService, + toasterServiceProvider ] }) export class AppModule { diff --git a/src/app/rxjs-operators.ts b/src/app/rxjs-operators.ts new file mode 100644 index 0000000..7e4249a --- /dev/null +++ b/src/app/rxjs-operators.ts @@ -0,0 +1,3 @@ +import 'rxjs/add/operator/toPromise'; +import 'rxjs/add/operator/map'; +import 'rxjs/add/operator/do'; \ No newline at end of file diff --git a/src/app/services/contact.resource.ts b/src/app/services/contact.resource.ts index 5415106..a38ae7e 100644 --- a/src/app/services/contact.resource.ts +++ b/src/app/services/contact.resource.ts @@ -1,35 +1,49 @@ -import * as angular from 'angular'; +import {Injectable} from "@angular/core"; +import {Http, URLSearchParams} from "@angular/http"; +@Injectable() export class Contact { private apiRoot: string = 'http://localhost:3000/contacts'; - private $http; - constructor($http) { - this.$http = $http; + constructor(private http: Http) { } - query(params: {string: string}) { - return this.$http.get(this.apiRoot, {params}); + static toURLSearchParams(params): URLSearchParams { + let search = new URLSearchParams(); + for (let key in params) search.append(key, params[key]) + return search; } - get(id, params?: {string: string}) { - return this.$http.get(this.apiRoot + '/' + id, {params}); + query(params?) { + let search = Contact.toURLSearchParams(params); + return this.http.get(this.apiRoot, {search}) + .map(res => res.json()) + .toPromise(); + } + + get(id, params?) { + let search = Contact.toURLSearchParams(params); + return this.http.get(this.apiRoot + '/' + id, {search}) + .map(res => res.json()) + .toPromise(); } save(data: any) { - return this.$http.post(this.apiRoot, data); + return this.http.post(this.apiRoot, data) + .map(res => res.json()) + .toPromise(); } update(data) { - return this.$http.put(this.apiRoot + '/' + data.id, data); + return this.http.put(this.apiRoot + '/' + data.id, data) + .map(res => res.json()) + .toPromise(); } remove(data) { - return this.$http.delete(this.apiRoot + '/' + data.id); + return this.http.delete(this.apiRoot + '/' + data.id) + .map(res => res.json()) + .toPromise(); } -} - -angular - .module('codecraft') - .service("Contact", Contact); \ No newline at end of file +} \ No newline at end of file diff --git a/src/app/services/contact.service.ts b/src/app/services/contact.service.ts index c47aa28..025c159 100644 --- a/src/app/services/contact.service.ts +++ b/src/app/services/contact.service.ts @@ -1,24 +1,24 @@ import * as angular from 'angular'; -export class ContactService { - private Contact; - private toaster; - private page = 1; - private hasMore = true; - private isLoading = false; - private isSaving = false; - private isDeleting = false; - private selectedPerson = null; - private persons = []; - private search = null; - private sorting = 'name'; - private ordering = 'ASC'; - - - constructor(Contact, toaster) { - this.Contact = Contact; - this.toaster = toaster; +import {Injectable, Inject} from "@angular/core"; +import {downgradeInjectable} from '@angular/upgrade/static'; +import {Toaster} from "../ajs-upgraded-providers"; +import {Contact} from "./contact.resource"; +@Injectable() +export class ContactService { + public page = 1; + public hasMore = true; + public isLoading = false; + public isSaving = false; + public isDeleting = false; + public persons = []; + public search = null; + public sorting = 'name'; + public ordering = 'ASC'; + + + constructor(private contact: Contact, @Inject(Toaster) private toaster) { this.loadContacts(); } @@ -48,18 +48,17 @@ export class ContactService { 'q': this.search }; - this.Contact.query(params).then(res => { + this.contact.query(params).then(res => { console.log(res); - for (let person of res.data) { + for (let person of res) { this.persons.push(person); } - if (!res.data) { + if (res.length === 0) { this.hasMore = false; } this.isLoading = false; }); } - }; loadMore() { @@ -72,7 +71,7 @@ export class ContactService { updateContact(person) { return new Promise((resolve, reject) => { this.isSaving = true; - this.Contact.update(person).then(() => { + this.contact.update(person).then(() => { this.isSaving = false; this.toaster.pop('success', 'Updated ' + person.name); resolve() @@ -83,11 +82,10 @@ export class ContactService { removeContact(person) { return new Promise((resolve, reject) => { this.isDeleting = true; - this.Contact.remove(person).then(() => { + this.contact.remove(person).then(() => { this.isDeleting = false; - let index = this.persons.indexOf(person); + var index = this.persons.indexOf(person); this.persons.splice(index, 1); - this.selectedPerson = null; this.toaster.pop('success', 'Deleted ' + person.name); resolve() }); @@ -97,9 +95,8 @@ export class ContactService { createContact(person) { return new Promise((resolve, reject) => { this.isSaving = true; - this.Contact.save(person).then(() => { + this.contact.save(person).then(() => { this.isSaving = false; - this.selectedPerson = null; this.hasMore = true; this.page = 1; this.persons = []; @@ -109,9 +106,9 @@ export class ContactService { }); }); }; -} +} angular .module('codecraft') - .service('ContactService', ContactService); \ No newline at end of file + .factory('ContactService', downgradeInjectable(ContactService)); \ No newline at end of file