Angular Communication Between Components

First example is from parent to child.

// parent.component.ts 

export class ParentComponent implements OnInit {

  textVarFromParent = 'Text to be passed to child component';

  ngOnInit(): void {
  }

}
// parent.component.html

<app-child [text]="textVarFromParent"></app-child>
// child.component.ts

export class ChildComponent implements OnInit {

  constructor () { }

  @Input() text: string;

  ngOnInit() { }
}
// child.component.html

{{ text }}

Child to parent.

// child.component.ts

export class ChildComponent implements OnInit {

  constructor() { }

  @Output() text = new EventEmitter<string>();

  ngOnInit(): void {
    this.text.emit('text from child');
  }

}
// app.component.html

<app-child (text)="textVarFromChild"></app-child>
// parent.component.ts

export class ParentComponent implements OnInit, OnChanges {

  textVarFromChild: string;

  ngOnChanges(): void {
    console.log(this.textVarFromChild);
  }

  ngOnInit(): void {
  }
}

More complex example.

// child.component.ts 

export class ChildComponent implements OnInit {

  constructor() { }

  @Output() text = new EventEmitter<string>();

  changeText(value: string) {
    console.log('From child component:' + value);
    this.text.emit(value);
  }

  ngOnInit(): void {
  }

}
// child.component.html

<button (click)="changeText('changed')">Change Text</button>
// parent.component.ts 

export class ParentComponent implements OnInit {

  changeText(value: string) {
    console.log('Parent component:' + value);
  }

  ngOnInit(): void {

  }
}
// parent.component.html

<app-child (text)="changeText($event)"></app-child>

Angular Async Pipe – Unsubscribe (Best Practices 2)

Use async pipe or unsubscribe properly.

For example if you ignite a http get request by visiting X component and then route to Y component without waiting your get request to complete, your get request in X component still runs.

There are several ways to handle that issue. First one is, using async pipe. Async pipe automatically unsubscribes when you change your route.

//example.component.ts

export class ExampleComponent implements OnInit {

    constructor(private http: HttpClient) { }
  
    recipes: Observable<any[]>;
  
    ngOnInit(): void {
      this.recipes = this.http.get<any[]>("URL").pipe();
    }
  
  }
// example.component.html

<ul>
<li *ngFor="let recipe of recipes | async">{{ recipe.title }}</li>
</ul>

Second way is to use unsubscribe in ngOnDestroy method.

export class ExampleComponent implements OnInit, OnDestroy {

    constructor(private http: HttpClient) { }
  
    subscription;
  
    ngOnDestroy(): void {
     this.subscription.unsubscribe();
    }
  
    ngOnInit(): void {
      this.subscription = this.http.get<any[]>("URL").subscribe();
    }
  
  }

Third way is to use subjects of RxJS.

export class ExampleComponent implements OnInit, OnDestroy {

  constructor(private http: HttpClient) { }

  unsubscribeSubject = new Subject();

  ngOnDestroy(): void {
   this.unsubscribeSubject.next();
   this.unsubscribeSubject.complete();
  }

  ngOnInit(): void {
    this.http.get<any[]>("URL")
    .pipe(takeUntil(this.unsubscribeSubject)).subscribe();
  }

}

Angular 9 Subscribe in Subscribe (Best Practices 1)

In some cases, for example you may need to get userId from httpclient request then use that userId in another client request. Well, if you’re a beginner you will think about to handle it in subscribe in subscribe.

Do not use subscribe in subscribe. Use mergeMap instead.

Here is my model file including Todo and User model.

// models.model.ts

export interface Todo {
    userId: number;
    id: number;
    title: string;
    completed: boolean;
}

export interface User {
    id: number;
    name: string;
    username: string;
    email: string;
    address: {
       street: string;
       suite: string;
       city: string;
       zipcode: string;
       geo: {
           lat: string;
           lng: string;
       }
    };
    phone: string;
    website: string;
    company: {
        name: string;
        catchPhrase: string;
        bs: string;
    };
}

My component which is using mergeMap.

// myapp/myapp.component.ts

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { mergeMap } from 'rxjs/operators';

import { Todo, User } from '../models.model';

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

export class MyappComponent implements OnInit {

constructor(private http: HttpClient) { }

todo: Todo;
user: User;

ngOnInit(): void {
this.http.get<Todo>('https://jsonplaceholder.typicode.com/todos/1')
.pipe(mergeMap((todo: Todo) => this.http.get<User>(`https://jsonplaceholder.typicode.com/users/${todo.userId}`))
)
.subscribe((user: User) => this.user = user);
}
}
    {{ user.id }}
    {{ user.name }}
    {{ user.username }}
    {{ user.email }}
    {{ user.address.city }}
    {{ user.address.geo.lat }}

React Hooks, JWT-Fetch Example

We have two states. First one is user and second one is list. In first state we are holding our user_token, token_type and expiration values.

Basically, we are running first useEffect when the page loads. It’s similar with ComponentDidMount(). We are being sure that user state is at is first state by checking with if block. Then first useEffect changes the user state by fetching user values to user state. Second useEffect is watching for changes in user state so, when user state changes it’s firing up second useEffect and it fetches our list. Also we are surrounding fetch with if block for being sure that second useEffect is not fired up when page loads first.

List holding only id and title in this example.

import React, { useEffect, useState } from 'react'

function App() {

  const [user, setUser] = useState(false)
  const [list, setList] = useState([])

  useEffect(() => {
    if (user === false) {
      let data = { email: 'LOGIN_USERNAME', password: 'LOGIN_PASSWORD' }
      fetch("LOGIN_URL",
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(data)
        }).then(res => res.json())
        .then(data => {
          setUser(data)
        }
        ).catch(err => console.log(err))
    }
  }, [user])


  useEffect(() => {
    if (user !== false) {
      fetch("FETCH_LIST_URL", {
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${user.access_token}`
        }
      }).then(res => res.json()).then(data => {
        setList([...list, data])
      }).catch(err => console.log(err))
    }
  }, [user])

  return (
    <>
      <h1>List</h1>
      {list !== undefined ? list.map(list => (<li key={list.id}>{list.title}</li>)) : "null"}
    </>
  );
}

export default App

React Hooks/useState Form Example

Working with React Hooks is fun. In this code example, i’m basically going to show you how to create a form in functional components with useState. Also my form will include checkboxes.

//Form.js
import React, { useState } from 'react'

export const Form = () => {
  const [input, setInput] = useState({})

  const handleChange = (e) => { 
    let { name, value, type, checked } = e.target
     value = type === "checkbox" ? checked : value

    setInput({
    ...input,
     [name]: value
  })
  }

  const handleSubmit = (e) => {
      e.preventDefault()
      console.log(input)
  }

  return (
    <form onSubmit={handleSubmit}>
        <label>Username:
        <input type="text" name="username" onChange={handleChange} /></label>
        <br/>
        <label>Password:
        <input type="text" name="password" onChange={handleChange} /></label>
        <br/>
        <input type="checkbox" name="male" onChange={handleChange} />Male<br/>
        <input type="checkbox" name="female" onChange={handleChange} />Female<br/>
        <input type="checkbox" name="none"  onChange={handleChange} />None of these<br/>
      <button>Submit</button>
    </form>
  )
}

In handleChange function we are checking the type of input and if input is checkbox, we’re assigning event.target.checked to value variable instead of event.target.value

Its’a basic component example. So if you want to run this, you need to include it in your App. Here is a simple example to how to include it.

//App.js

import React from 'react'
import { Form } from './Form'

function App() {
  return ( <div><Form/></div> )
}

Finally your index.js

//index.js
//...your imports...
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
//..your imports...

ReactDOM.render(<App />, document.getElementById('root'));