Angular 7

Installation

npm install -g @angular/cli
ng new myweb
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? SCSS   [ http://sass-lang.com   ]

Angular 7 Components

cd miweb
ng serve -o
/app.component.html
/app.component.scss
/app.component.ts
> ng generate component nav
// output

> ng g c about
// output

> ng g c contact
// output

> ng g c home
// output

Angular 7 Templating

app.component.html

<app-nav></app-nav>

<section>
  <router-outlet></router-outlet>
</section>

nav.component.html

<header>
  <div class="container">
    <a routerLink="/" class="logo">My Web</a>
    <nav>
      <ul>
        <li><a routerLink="/">Home</a></li>
        <li><a routerLink="/about">About</a></li>
        <li><a routerLink="/contact">Contact us</a></li>
      </ul>
    </nav>
  </div>
</header>
<!-- From: -->
<a routerLink="/" class="logo">My Web</a>

<!-- To: -->
<a routerLink="/" class="logo">{{ appTitle }}</a>

nav.component.ts

export class NavComponent implements OnInit {

  appTitle: string = 'My Web Site';
  // OR (either will work)
  appTitle = 'My Web Site';

  constructor() { }

  ngOnInit() {
  }

}

/src/styles.scss

@import url('https://fonts.googleapis.com/css?family=Montserrat:400,700');

body, html {
    height: 100%;
    margin: 0 auto;
}

body {
    font-family: 'Montserrat';
    font-size: 18px;
}

a {
    text-decoration: none;
}

.container {
    width: 80%;
    margin: 0 auto;
    padding: 1.3em;
    display: grid;
    grid-template-columns: 30% auto;

    a {
        color: white;
    }
}

section {
    width: 80%;
    margin: 0 auto;
    padding: 2em;
}

nav/component.scss

header {
    background: #7700FF;

    .logo {
        font-weight: bold;
    }

    nav {
        justify-self: right;
    
        ul {
            list-style-type: none;
            margin: 0; padding: 0;

            li {
                float: left;

                a {
                    padding: 1.5em;
                    text-transform: uppercase;
                    font-size: .8em;

                    &:hover {
                        background: #8E2BFF;
                    }
                }
            }
        }
    }
}

Angular 7 Routing

/src/app/app-routing.module.ts

// Other imports removed for brevity

import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { ContactComponent } from './contact/contact.component';

const routes: Routes = [
  { path: '', component: HomeComponent },
  { path: 'about', component: AboutComponent },
  { path: 'contact', component: ContactComponent },
];

// Other code removed for brevity

Angular 7 Event Binding

/src/app/home/home.component.html 

<h1>Home</h1>

<button (click)="firstClick()">Click me</button>

home.component.ts

export class HomeComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }

  firstClick() {
    console.log('clicked');
  }

}
(focus)="myMethod()"
(blur)="myMethod()" 
(submit)="myMethod()"  
(scroll)="myMethod()"

(cut)="myMethod()"
(copy)="myMethod()"
(paste)="myMethod()"

(keydown)="myMethod()"
(keypress)="myMethod()"
(keyup)="myMethod()"

(mouseenter)="myMethod()"
(mousedown)="myMethod()"
(mouseup)="myMethod()"

(click)="myMethod()"
(dblclick)="myMethod()"

(drag)="myMethod()"
(dragover)="myMethod()"
(drop)="myMethod()"

Angular 7 Class & Style Binding

home.component.html

<h1 [class.gray]="h1Style">Home</h1>

home.component.ts

  h1Style: boolean = false;

  constructor() { }

  ngOnInit() {
  }

  firstClick() {
    this.h1Style = true;
  }

home.component.scss

.gray {
    color: gray;
}

home.component.html

<h1 [ngClass]="{
  'gray': h1Style,
  'large': !h1Style
}">Home</h1>

home.component.scss

.large {
    font-size: 4em;
}

home.component.html

<h1 [style.color]="h1Style ? 'gray': 'black'">Home</h1>

<h1 [ngStyle]="{
  'color': h1Style ? 'gray' : 'black',
  'font-size': !h1Style ? '1em' : '4em'
}">Home</h1>

Angular 7 Services

> ng generate service data

/src/app/data.service.ts

// Other code removed for brevity

export class DataService {

  constructor() { }

  firstClick() {
    console.log('clicked');
  }
}

/src/app/home/home.component.ts

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

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {

  constructor(private data: DataService) { }

  ngOnInit() {
  }

  firstClick() {
    this.data.firstClick();
  }

}

Angular 7 HTTP Client

/src/app/app.module.ts

// Other imports
import { HttpClientModule } from '@angular/common/http';

...

  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,    // <-- Right here
  ],

/src/app/data.service.ts

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';  // Import it up here

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

  constructor(private http: HttpClient) { }

  getUsers() {
    return this.http.get('https://reqres.in/api/users');
  }
}

home.component.ts

export class HomeComponent implements OnInit {

  users: Object;

  constructor(private data: DataService) { }

  ngOnInit() {
    this.data.getUsers().subscribe(data => {
        this.users = data
        console.log(this.users);
      }
    );
  }

}

home.component.html

<h1>Users</h1>

<ul *ngIf="users">
  <li *ngFor="let user of users.data">
    <img [src]="user.avatar">
    <p>{{ user.first_name }} {{ user.last_name }}</p>
  </li>
</ul>

home.component.scss

ul {
    list-style-type: none;
    margin: 0;padding: 0;

    li {
        background: rgb(238, 238, 238);
        padding: 2em;
        border-radius: 4px;
        margin-bottom: 7px;
        display: grid;
        grid-template-columns: 60px auto;

        p {
            font-weight: bold;
            margin-left: 20px;
        }

        img {
            border-radius: 50%;
            width: 100%;
        }
    }
}

Angular 7 Forms

app.module.ts

// other imports
import { ReactiveFormsModule } from '@angular/forms';

// other code
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    ReactiveFormsModule  // <- Add here
  ],

 contact.component.ts

import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';

@Component({
  selector: 'app-contact',
  templateUrl: './contact.component.html',
  styleUrls: ['./contact.component.scss']
})

export class ContactComponent implements OnInit {

  messageForm: FormGroup;
  submitted = false;
  success = false;

  constructor(private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.messageForm = this.formBuilder.group({
      name: ['', Validators.required],
      message: ['', Validators.required]
    });
  }

  onSubmit() {
    this.submitted = true;

    if (this.messageForm.invalid) {
        return;
    }

    this.success = true;
  }
}

contact.component.html

<h1>Contact us</h1>

<form [formGroup]="messageForm" (ngSubmit)="onSubmit()">

    <h5 *ngIf="success">Your form is valid!</h5>

    <label>
      Name:
      <input type="text" formControlName="name">
      <div *ngIf="submitted && messageForm.controls.name.errors" class="error">
        <div *ngIf="messageForm.controls.name.errors.required">Your name is required</div>
      </div>
    </label>
  
    <label>
      Message:
      <textarea formControlName="message"></textarea>
      <div *ngIf="submitted && messageForm.controls.message.errors" class="error">
        <div *ngIf="messageForm.controls.message.errors.required">A message is required</div>
      </div>
    </label>

    <input type="submit" value="Send message" class="cta">
  
  </form>

  <div *ngIf="submitted" class="results">
    <strong>Name:</strong> 
    <span>{{ messageForm.controls.name.value }}</span>

    <strong>Message:</strong> 
    <span>{{ messageForm.controls.message.value }}</span>
  </div>

contact.component.scss

label {
    display: block;
    
    input, textarea {
        display: block;
        width: 50%;
        margin-bottom: 20px;
        padding: 1em;
    }

    .error {
        margin-top: -20px;
        background: yellow;
        padding: .5em;
        display: inline-block;
        font-size: .9em;
        margin-bottom: 20px;
    }
}

.cta {
    background: #7700FF;
    border: none;
    color: white;

    text-transform: uppercase;
    border-radius: 4px;
    padding: 1em;
    cursor: pointer;
    font-family: 'Montserrat';
}

.results {
    margin-top: 50px;

    strong {
        display: block;
    }
    span {
        margin-bottom: 20px;
        display: block;
    }
}