Wednesday, June 25, 2025

Angular: @Input @Output; React: Just JavaScript

Angular @Input @Output

Parent HTML:
<div style="border: 1px solid green; padding: 10px;">
  <h2>Home Component</h2>
  <p>Routing message: {{ (routeData$ | async)?.message }}</p>
  <button (click)="increase()">Increase</button>
  <app-contact-us [phoneNumber]="myPhone.toString()" mainOffice="something" [initialEmployeeCount]="homeEmployeeCount"
    (onEmployeeCountChanged)="handleEmployeeCountChanged($event)"></app-contact-us>
  <hr />
  Parent employee count: {{homeEmployeeCount}}
  <br/>
</div>
Parent TypeScript:
import { AsyncPipe, JsonPipe } from '@angular/common';
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { map, Observable, tap } from 'rxjs';
import { ContactUs } from './contact-us/contact-us';
import { HomeResolverData } from '../../resolvers/home.resolver';

@Component({
  selector: 'app-home',
  imports: [AsyncPipe, ContactUs],
  templateUrl: './home.html',
  styles: ``,
})
export class Home implements OnInit {
  /**
   *
   */

  myPhone = 1314;
  homeEmployeeCount = 7;

  routeData$!: Observable<HomeResolverData>;

  constructor(private route: ActivatedRoute) {
    // console.log(JSON.stringify(this.route.data));
    // console.log(this.routeData$);
  }
  ngOnInit(): void {
    this.routeData$ = this.route.data.pipe(
      map((resolved) => resolved['homeResolver'] as HomeResolverData),
      tap((data) =>
        console.log(
          'RESOLVER_DATA_CONSUMED: Resolver data is now available in component:',
          data
        )
      )
    );
  }

  increase() {
    ++this.myPhone;
  }

  handleEmployeeCountChanged($event: number) {
    this.homeEmployeeCount = $event;
  }
}
Child HTML:
<div>

  <h4>Contact Us</h4>


  Phone: {{phoneNumber}}<br/>
  Main Office: {{primaryOffice}}<br/>

  <button (click)="welcomeEmployee()">Welcome employee</button>
</div>
Child TypeScript:
import { Component, EventEmitter, Input, Output } from '@angular/core';

@Component({
  selector: 'app-contact-us',
  imports: [],
  templateUrl: './contact-us.html',
  styles: ``
})
export class ContactUs {
    @Input() phoneNumber = '';
    @Input('mainOffice') primaryOffice!: string;

    @Input() initialEmployeeCount = 0;
    @Output() onEmployeeCountChanged = new EventEmitter<number>();

    welcomeEmployee() {
      ++this.initialEmployeeCount;
      this.onEmployeeCountChanged.emit(this.initialEmployeeCount);
    }


}


React

Parent HTML+TypeScript:
import { useLoaderData } from "react-router";
import { ContactUs } from "./Home/ContactUs";
import { useState } from "react";

export default function Home() {
    const homeData = useLoaderData();

    const [myPhone, setMyPhone] = useState(1314);
    const [homeEmployeeCount, setHomeEmployeeCount] = useState(7);

    return (
        <>
            <h2>Home Component</h2>
            <p>Routing message: {homeData.message}</p>
            <button onClick={increase}>Increase</button>
            <ContactUs
                phoneNumber={myPhone.toString()}
                mainOffice="something"
                initialEmployeeCount={homeEmployeeCount}
                onEmployeeCountChanged={handleEmployeeCountChanged}
            />
            <hr />
            <button onClick={batchIncreaseFlawed}>Batch Increase Flawed</button>
            <button onClick={batchIncreaseCorrect}>
                Batch Increase Correct
            </button>
            <hr />
            Parent employee count: {homeEmployeeCount}
        </>
    );

    function handleEmployeeCountChanged(newCount: number) {
        setHomeEmployeeCount(newCount);
    }

    function batchIncreaseFlawed() {
        setMyPhone(myPhone + 1);
        setMyPhone(myPhone + 1);
        setMyPhone(myPhone + 1);
    }

    function batchIncreaseCorrect() {
        setMyPhone((prev) => prev + 1);
        setMyPhone((prev) => prev + 1);
        setMyPhone((prev) => prev + 1);
    }

    function increase() {
        setMyPhone((prev) => prev + 1);
    }
}
Child HTML+TypeScript:
import { useState } from "react";

type Params = {
    phoneNumber: string;
    mainOffice: string;
    initialEmployeeCount: number;
    onEmployeeCountChanged: (newCount: number) => void;
};

export function ContactUs({
    phoneNumber,
    mainOffice: primaryOffice,
    initialEmployeeCount,
    onEmployeeCountChanged,
}: Params) {
    const [employeeCount, setEmployeeCount] = useState(initialEmployeeCount);

    return (
        <div>
            <h4>Contact Us</h4>
            Phone: {phoneNumber} <br />
            Main Office: {primaryOffice}<br />
            
            <button onClick={welcomeEmployee}>Welcome employee</button>
        </div>
    );

    function welcomeEmployee() {
        setEmployeeCount((prev) => prev + 1);
        onEmployeeCountChanged(employeeCount);
    }
}
Angular: @Input @OutputReact's Angular @Input @Output

No comments:

Post a Comment