Services, HTTP, Input & Output

What is Services?

  • Classes that can send functionality and data across multiple components.
  • Keeps components lean
  • DRY – Don’t repeat yourself
  • Ideal place for Ajax calls using the HTTP requests module

Create a new file

/services/my-service.service.ts
  • Import @Injectable and create class
  • Add as a provider to @ngModule
  • Call from components

Generating Services with Angular-CLI

ng g service services/my-service

Add the “module=app.module” flag to automatically add as a provider

ng g s services/data --module=app.module

services/data.service.ts

import { Injectable } from '@angular/core';

import { User } from '../models/User';

@Injectable()
export class DataService {
  users: User[];

  constructor() { 
    this.users = [
      { 
        firstName: 'John',
        lastName: 'Doe',
        email: 'john@gmail.com',
        isActive: true,
        registered: new Date('01/02/2018 08:30:00'),
        hide: true
      },
      {
        firstName: 'Kevin',
        lastName: 'Johnson',
        email: 'kevin@yahoo.com',
        isActive: false,
        registered: new Date('03/11/2017 06:20:00'),
        hide: true
      },
      {
        firstName: 'Karen',
        lastName: 'Williams',
        email: 'karen@gmaial.com',
        isActive: true,
        registered: new Date('11/02/2016 10:30:00'),
        hide: true
      }
    ];
  }

  getUsers(): User[] {
    console.log('Fetching users from service...');
    return this.users;
  }

  addUser(user: User) {
    this.users.unshift(user);
  }

}

Component.ts

import { Component, OnInit, ViewChild } from '@angular/core';
import { DataService } from '../../services/data.service';
import { User } from '../../models/User'; 

@Component({
  selector: 'app-users',
  templateUrl: './users.component.html',
  styleUrls: ['./users.component.css']
})
export class UsersComponent implements OnInit {
  user: User = {
    firstName: '',
    lastName: '',
    email: ''
  }
  users: User[];
  showExtended: boolean = true;
  loaded: boolean = false;
  enableAdd: boolean = false;
  showUserForm: boolean = false;
  @ViewChild('userForm') form: any;

  constructor(private dataService: DataService) { }

  ngOnInit() {
   
      this.users = this.dataService.getUsers();

      this.loaded = true;
  }

  onSubmit({value, valid}: {value: User, valid: boolean}) {
    if(!valid){
      console.log('Form is not valid');
    } else {
      value.isActive = true;
      value.registered = new Date();
      value.hide = true;

      this.dataService.addUser(value);

      this.form.reset();
    }
  }

  
}

HTML

<button (click)="showUserForm = !showUserForm" class="btn btn-dark mb-3">Add User</button>
<div class="card card-body mb-3" *ngIf="showUserForm">
  <h2>Add User</h2>
  <form #userForm="ngForm" (ngSubmit)="onSubmit(userForm)">
    <div class="form-group">
      <label>First Name</label>
      <input 
        type="text" 
        [(ngModel)]="user.firstName" 
        [ngClass]="{'is-invalid':userFirstName.errors && userFirstName.touched}"
        class="form-control" 
        name="firstName"
        #userFirstName="ngModel"
        required
        minlength="2"
      >
      <div [hidden]="!userFirstName.errors?.required" class="invalid-feedback">
        First name required
      </div>

      <div [hidden]="!userFirstName.errors?.minlength" class="invalid-feedback">
          Must be at least 2 characters
      </div>
    </div>
    <div class="form-group">
      <label>Last Name</label>
      <input 
        type="text" 
        [(ngModel)]="user.lastName" 
        [ngClass]="{'is-invalid':userLastName.errors && userLastName.touched}"
        class="form-control" 
        name="lastName"
        #userLastName="ngModel"
        required
        minlength="2"
      >
      <div [hidden]="!userLastName.errors?.required" class="invalid-feedback">
        Last name required
      </div>

      <div [hidden]="!userLastName.errors?.minlength" class="invalid-feedback">
          Must be at least 2 characters
      </div>
    </div>
    <div class="form-group">
      <label>Email</label>
      <input 
      type="email" 
      [(ngModel)]="user.email" 
      [ngClass]="{'is-invalid':userEmail.errors && userEmail.touched}"
      class="form-control" 
      name="email"
      #userEmail="ngModel"
      required
      pattern="[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
    >
    <div [hidden]="!userEmail.errors?.required" class="invalid-feedback">
      Email name required
    </div>

    <div [hidden]="!userEmail.errors?.pattern" class="invalid-feedback">
        Email is not valid
    </div>
    </div>

    <button [disabled]="!userForm.form.valid" class="btn btn-block mb-3">Add New User</button>
  </form>
</div>
<ul class="list-unstyled" *ngIf="loaded && users?.length > 0">
  <li class="card card-body mb-2" *ngFor="let user of users" [class.bg-light]="user.isActive">
    <h3>{{ user.firstName }} {{ user.lastName }}
      <small>
        <button (click)="user.hide = !user.hide" class="btn btn-dark btn-sm">
          <i [ngClass]="user.hide ? 'fa fa-plus' : 'fa fa-minus'"></i>
        </button>
      </small>
    </h3>
    <ul class="list-group" *ngIf="!user.hide">
      <li class="list-group-item">Emial: {{ user.email }}</li>
      <li class="list-group-item">Joined: {{ user.registered | date }}</li>
    </ul>
  </li>
</ul>

<h4 *ngIf="users?.length == 0">No Users Found</h4>

<h4 *ngIf="!loaded">Loading Users...</h4>
Was this page helpful?