> For the complete documentation index, see [llms.txt](https://duncanhunter.gitbook.io/angular-and-ngrx/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://duncanhunter.gitbook.io/angular-and-ngrx/11.-create-eventservice.md).

# 11. Create EventService

## [Link to Section Slides](https://docs.google.com/presentation/d/1Y7Tf7kjO4Li0ihhkVgRjn4szFJPAkbMvilfrDCbrjq8/edit#slide=id.g2fa7fd70ec_0_536)

## 1. Add an Angular service and return an observable of Attendee

* Make an Angular service.
* Run the following command to make a service.

```
ng g service event/services/event
```

## 2. Add logic to the service

* Add logic to the  `EventService` to return a hardcoded `Attendee` observable array.

{% code title="src/app/event/services/event.service.ts" %}

```typescript
import { Injectable } from '@angular/core';
import { Attendee } from '../../models';
import { Observable, of } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class EventService {
  constructor() {}

  getAttendees(): Observable<Attendee[]> {
    return of([
      {
        name: 'Duncan',
        attending: true,
        guests: 0
      }
    ] as Attendee[]);
  }
}
```

{% endcode %}

## 3. Inject service into the component

* Inject and use the new service in the component.
* Subscribe to the observable of Attendee returned from the service.
* Add a getAttendees method to the component.

{% code title="src/app/event/containers/event/event.component.ts" %}

```typescript
import { Component, OnInit } from '@angular/core';
import { Attendee } from '../../../models';
import { EventService } from '../../services/event.service';

@Component({
  selector: 'app-event',
  templateUrl: './event.component.html',
  styleUrls: ['./event.component.scss']
})
export class EventComponent implements OnInit {  
  attendees: Attendee[] = [];
  constructor(private eventService: EventService) {}

  ngOnInit() {
    this.getAttendees();
  }

  getAttendees() {
    this.eventService
      .getAttendees()
      .subscribe(attendees => (this.attendees = attendees));
  }

  addAttendee(attendee: Attendee) {
    this.attendees = [...this.attendees, attendee];
    console.log(
      'TCL: EventComponent -> addAttendee -> this.attendees',
      this.attendees
    );
  }
}
```

{% endcode %}

## 4. Swap from subscription to async pipe

Angular [pipes](https://angular.io/guide/pipes), a way to write display-value transformations that you can declare in your HTML. The async pipe is a special built in pipe from Angular that will subscribe to an observable for you in the HTML template and also unsubscribe when the components `ngOnDestory` life cycle hook is fired. Another quirk is that it will also mark the component to be checked by Angular's  change detection on its next cycle.

* Use async pipe versus a subscription to get the attendees from the observable.

{% code title="src/app/event/containers/event/event.component.ts" %}

```typescript
import { Component, OnInit } from '@angular/core';
import { Attendee } from '../../../models';
import { EventService } from '../../services/event.service';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-event',
  templateUrl: './event.component.html',
  styleUrls: ['./event.component.scss']
})
export class EventComponent implements OnInit {
  attendees$: Observable<Attendee[]>;

  constructor(private eventService: EventService) {}

  ngOnInit() {
    this.getAttendees();
  }

  getAttendees() {
    this.attendees$ = this.eventService.getAttendees();
  }
}
```

{% endcode %}

## 5. Use async pipe in HTML

* Swap out attendee for `attendee$ | async` in the HTML. We can leave the original attendees property alone for now.

{% code title="src/app/event/containers/event/event.component.html" %}

```markup
<app-add-attendee (addAttendee)="addAttendee($event)"></app-add-attendee>
<app-event-list [attendees]="attendees$ | async"></app-event-list>
```

{% endcode %}

## 6. Add fake backend

Angular's own `HttpClientInMemoryWebApiModule` can help us make a little mock server without needing to add a real server set up. You can read more about how it works here <https://github.com/angular/in-memory-web-api>.

* Add fake backend with with npm.

```
npm i angular-in-memory-web-api -D
```

* Add `HttpClientModule`
* Add the `HttpClientInMemoryWebApiModule` to the imports array of the `@ngModule` and register the `InMemoryDataService` we will write in the next step.

{% code title="src/app/app.module.ts" %}

```typescript
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { RouterModule } from '@angular/router';

import { AppComponent } from './app.component';
import { HomeComponent } from './home/containers/home/home.component';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';
import { InMemoryDataService } from './app.db';
@NgModule({
  declarations: [AppComponent, HomeComponent],
  imports: [
    BrowserModule,
    RouterModule.forRoot([
      { path: '', pathMatch: 'full', redirectTo: 'home' },
      { path: 'home', component: HomeComponent },
      { path: 'event', loadChildren: './event/event.module#EventModule' }
    ]),
    HttpClientModule,
    HttpClientInMemoryWebApiModule.forRoot(InMemoryDataService, { delay: 100 }),
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}
```

{% endcode %}

## 7.  Make the InMemoryDataService

* Create the missing `InMemoryDataService` in the src/app folder. Do not worry too much about learning how this works we just need a little fake backend so we can focus on understanding Angular and NgRx.

{% code title="src/app/app.db.ts" %}

```typescript
import { InMemoryDbService } from 'angular-in-memory-web-api';
import { Attendee } from './models';

export class InMemoryDataService implements InMemoryDbService {
  createDb() {
    const attendees = [
      {
        id: 1,
        name: 'Duncan In Memory',
        attending: true,
        guests: 0
      }
    ] as Attendee[];
    return { attendees };
  }
}
```

{% endcode %}

## 8. Update Attendee interface to have an optional Id

* Add optional id to Attendee interface with a `id?: number` syntax.

{% code title="src/app/models/attendee.ts" %}

```typescript
export interface Attendee {
  id?: number;
  name: string;
  attending: boolean;
  guests: number;
}
```

{% endcode %}

## 9. Add HttpClientModule to EventModule

Angular modules describe the dependencies for this section of code so we will need to also add the HttpClientModule here to. The build tool is smart enough to know we registered it in the root module so we will not pay for it twice in the browser bundled JavaScript.

* Add `HttpClientModule` to the EventModule.

{% code title="src/app/event/event.module.ts" %}

```typescript
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { HttpClientInMemoryWebApiModule } from 'angular-in-memory-web-api';

import { EventComponent } from './containers/event/event.component';
import { AddAttendeeComponent } from './components/add-attendee/add-attendee.component';
import { EventListComponent } from './components/event-list/event-list.component';
@NgModule({
  imports: [
    CommonModule,
    RouterModule.forChild([{ path: '', component: EventComponent }]),
    ReactiveFormsModule,
    HttpClientModule
  ],
  declarations: [EventComponent, AddAttendeeComponent, EventListComponent]
})
export class EventModule {}
```

{% endcode %}

## 10.  Update service to call fake endpoint

* Update the service by injecting the `httpClient` into the constructor.
* Change the `getAttendee` method to use the `httpClient` and fake backend.
* Add an `addAttendee` method to save the added attendees.

{% code title="src/app/event/event.service.ts" %}

```typescript
import { Injectable } from '@angular/core';
import { Attendee } from '../../models';
import { Observable, of } from 'rxjs';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class EventService {
  constructor(private httpClient: HttpClient) {}

  getAttendees(): Observable<Attendee[]> {
    return this.httpClient.get<Attendee[]>('/api/attendees');
  }

  addAttendee(attendee: Attendee): Observable<Attendee> {
    return this.httpClient.post<Attendee>('/api/attendees', attendee);
  }
}
```

{% endcode %}

## 12. Update container component to have an add attendee method

* Add new method to call `addAttendee` on the service and then call `getAttendees` after it saves.

{% code title="src\app\event\containers\event\event.component.ts" %}

```typescript
import { Component, OnInit } from '@angular/core';
import { Attendee } from '../../../models';
import { EventService } from '../../services/event.service';
import { Observable } from 'rxjs';

@Component({
  selector: 'app-event',
  templateUrl: './event.component.html',
  styleUrls: ['./event.component.scss']
})
export class EventComponent implements OnInit {
  attendees$: Observable<Attendee[]>;

  constructor(private eventService: EventService) {}

  ngOnInit() {
    this.getAttendees();
  }

  getAttendees() {
    this.attendees$ = this.eventService.getAttendees();
  }

  addAttendee(attendee: Attendee) {
    this.eventService
      .addAttendee(attendee)
      .subscribe(() => this.getAttendees());
  }
}
```

{% endcode %}

## StackBlitz Link

{% embed url="<https://stackblitz.com/github/duncanhunter/angular-and-ngrx-demo-app/tree/11-create-event-service>" %}
Web Link: Link to the demo app running in StackBlitz
{% endembed %}
