1. publisher does not produce data unless subscriber requests for it.
  2. publisher will produce only <= subscriber requested items. publisher can also produce 0 items!
  3. subscriber can cancel the subscription. producer should stop at that moment as subscriber is no longer interested in consuming the data
  4. producer can send the error signal

  1. PublisherImpl instance would call the subscribe method and pass instance of SubscriberImpl
  2. PublisherImpl subscribe method would inturn call the onSubscribe method using the instance of SubscriberImpl passed.
  3. SubscriberImpl would get the same subscription which it has been passed to publisherImpl subscribe method earlier
  4. PublisherImpl has following methods
    • subscribe – takes subscriber as argument and creates new subscription and notify the subscriber by calling the onSubscribe method
      public void subscribe(Subscriber subscriber) {
              var subscription = new SubscriptionImpl(subscriber);
              subscriber.onSubscribe(subscription);
      }
      
  5. SubscriberImpl has following methods
    • onSubscribe – To get the same subscription passed to publisher subscribe method. This is inturn called from publisherImpl
    • onNext – called from subscriptionImpl to pass the data during iteration
    • onError – called from subscriptionImpl during error
    • onComplete – called from when all data is completed
    @Override
        public void onSubscribe(Subscription subscription) {
            this.subscription = subscription;
        }
    
        @Override
        public void onNext(String emailId) {
            logger.info("Received {}", emailId);
        }
    
        @Override
        public void onError(Throwable throwable) {
            logger.info("---------------------------------------------");
            logger.info("Received error {}", throwable.getMessage());
        }
    
        @Override
        public void onComplete() {
            logger.info("Subscription ended");
        }
    
  6. SubscriptionImplhas following methods
    • request – you can request date using subscriptionImpl instance by passing no of records
    • cancel – cancel subscription
    @Override
        public void request(long requestedItemCnt) {
            if(isCancelled){
                return;
            }
    
            logger.info("Subscriber has requested {} items ", requestedItemCnt);
    
            if(requestedItemCnt >MAX_ITEMS){
                this.subscriber.onError(new RuntimeException(" Items requested is more than Total Items Available"));
                this.isCancelled = true;
                return;
            }
    
            //Check if all items(MAX_ITEMS) were sent
            for(int idx=0;idx<requestedItemCnt && count<MAX_ITEMS; idx++){
                count++;
                this.subscriber.onNext(this.faker.internet().emailAddress());
            }
    
            //If all items were sent complete subscription
            if(count == MAX_ITEMS){
                logger.info("No More data from Producer");
                this.subscriber.onComplete();
                isCancelled = true;
            }
        }
    
        @Override
        public void cancel() {
            logger.info("Cancelling Subscription... . . .");
            isCancelled = true;
        }
    

pom.xml

  <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.projectreactor.netty</groupId>
            <artifactId>reactor-netty-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.projectreactor.netty</groupId>
            <artifactId>reactor-netty-http</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>${logback.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.javafaker</groupId>
            <artifactId>javafaker</artifactId>
            <version>${faker.version}</version>
        </dependency>

PublisherImpl.java

import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;

public class PublisherImpl implements Publisher {
    @Override
    public void subscribe(Subscriber subscriber) {
        var subscription = new SubscriptionImpl(subscriber);
        subscriber.onSubscribe(subscription);
    }
}

SubscriptionImpl.java

public class SubscriptionImpl implements Subscription {
    private static final Logger logger = LoggerFactory.getLogger(SubscriptionImpl.class);
    private final Subscriber<? super String> subscriber;
    private boolean isCancelled = false;
    private final Faker faker;

    private final int MAX_ITEMS = 10;
    private static int count = 0;


    public SubscriptionImpl(Subscriber subscriber){
        this.subscriber = subscriber;
        this.faker = Faker.instance();
    }

    @Override
    public void request(long requestedItemCnt) {
        if(isCancelled){
            return;
        }

        logger.info("Subscriber has requested {} items ", requestedItemCnt);

        if(requestedItemCnt >MAX_ITEMS){
            this.subscriber.onError(new RuntimeException(" Items requested is more than Total Items Available"));
            this.isCancelled = true;
            return;
        }

        //Check if all items(MAX_ITEMS) were sent
        for(int idx=0;idx<requestedItemCnt && count<MAX_ITEMS; idx++){
            count++;
            this.subscriber.onNext(this.faker.internet().emailAddress());
        }


        //If all items were sent complete subscription
        if(count == MAX_ITEMS){
            logger.info("No More data from Producer");
            this.subscriber.onComplete();
            isCancelled = true;
        }
    }

    @Override
    public void cancel() {
        logger.info("Cancelling Subscription... . . .");
        isCancelled = true;
    }
}

SubscriberImpl.java

import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SubscriberImpl implements Subscriber<String> {
    private static final Logger logger = LoggerFactory.getLogger(SubscriberImpl.class);
    private Subscription subscription;

    @Override
    public void onSubscribe(Subscription subscription) {
        this.subscription = subscription;
    }

    @Override
    public void onNext(String emailId) {
        logger.info("Received {}", emailId);
    }

    @Override
    public void onError(Throwable throwable) {
        logger.info("---------------------------------------------");
        logger.info("Received error {}", throwable.getMessage());
    }

    @Override
    public void onComplete() {
        logger.info("Subscription ended");
    }

    public Subscription getSubscription() {
        return subscription;
    }
}

Main.java

import org.mugil.publisher.PublisherImpl;
import org.mugil.subscriber.SubscriberImpl;

import java.time.Duration;

public class Main {
    public static void main(String[] args) throws InterruptedException {
        getMessages();
    }

    public static void getMessages() throws InterruptedException {
        var objPublisher = new PublisherImpl();
        var objSubscriber = new SubscriberImpl();

        objPublisher.subscribe(objSubscriber);
        objSubscriber.getSubscription().request(1);
        Thread.sleep(Duration.ofSeconds(2));

        objSubscriber.getSubscription().request(2);
        Thread.sleep(Duration.ofSeconds(2));

        objSubscriber.getSubscription().request(3);
        Thread.sleep(Duration.ofSeconds(2));

        objSubscriber.getSubscription().cancel();

        objSubscriber.getSubscription().request(1);
    }
}

Output

18:00:57.240 [main] INFO org.mugil.publisher.SubscriptionImpl -- Subscriber has requested 1 items 
18:00:57.534 [main] INFO org.mugil.subscriber.SubscriberImpl -- Received jani.mante@gmail.com
18:00:59.537 [main] INFO org.mugil.publisher.SubscriptionImpl -- Subscriber has requested 2 items 
18:00:59.541 [main] INFO org.mugil.subscriber.SubscriberImpl -- Received sunny.quigley@yahoo.com
18:00:59.544 [main] INFO org.mugil.subscriber.SubscriberImpl -- Received hang.gutkowski@yahoo.com
18:01:01.546 [main] INFO org.mugil.publisher.SubscriptionImpl -- Subscriber has requested 3 items 
18:01:01.548 [main] INFO org.mugil.subscriber.SubscriberImpl -- Received malik.thiel@hotmail.com
18:01:01.549 [main] INFO org.mugil.subscriber.SubscriberImpl -- Received andre.purdy@gmail.com
18:01:01.550 [main] INFO org.mugil.subscriber.SubscriberImpl -- Received kim.greenfelder@gmail.com
18:01:03.560 [main] INFO org.mugil.publisher.SubscriptionImpl -- Cancelling Subscription... . . .

Mono is a type of instant Publisher that represents a single or empty value. This means it can emit only one value at most for the onNext() request and then terminates with the onComplete() signal. In case of failure, it only emits a single onError() signal.Most Mono implementations are expected to immediately call onComplete on their Subscriber after having called onNext.a combination of onNext and onError is explicitly forbidden.

Overridden Lambda implementation available in mono

subscribe();  //1

subscribe(Consumer<? super T> consumer);  //2

subscribe(Consumer<? super T> consumer,
          Consumer<? super Throwable> errorConsumer);  //3

subscribe(Consumer<? super T> consumer,
          Consumer<? super Throwable> errorConsumer,
          Runnable completeConsumer);  //4

subscribe(Consumer<? super T> consumer,
          Consumer<? super Throwable> errorConsumer,
          Runnable completeConsumer,
          Consumer<? super Subscription> subscriptionConsumer); //5

//1

        Publisher<String> rctMono  = Mono.just("Hello React"); // Simple Mono Publisher using Just
        var subs = new SubscriberImpl();
        rctMono.subscribe(subs);
        subs.getSubscription().request(10);

Output

08:21:46.241 [main] INFO org.mugil.subscriber.SubscriberImpl -- Received Hello React
08:21:46.252 [main] INFO org.mugil.subscriber.SubscriberImpl -- Subscription ended

//5


       Mono<Integer> rctMono2 = Mono.just(1)
                                    .map(i -> i/0);
       rctMono2.subscribe(i -> System.out.println(i),   //Consumer
                          err -> System.out.println("Error Msg -" + err.getMessage()), //onError, Not Mandatory
                          () -> System.out.println("Completed"), //onComplete, Not Mandatory
                          subscription -> subscription.request(1)); //onRequest, Not Mandatory

Output

Error Msg -/ by zero

Simple code which returns Mono based on switch case

    public static Mono<String> getUserName(Integer num){
        return switch (num){
            case 1 -> Mono.just("How are you");
            case 2 -> Mono.empty();
            default -> Mono.error(new RuntimeException("Invalid Input"));
        };
    }

Using mono.just would invoke the sumOfNums as it always fetches value from JVM memory rather than streaming

public static void main(String[] args) {
  List<Integer> lstNums = List.of(1,2,3);
  Mono.just(sumOfNums(lstNums)); //Mono.just takes the value from memory so wont be suitable for streaming data incase large data should be handled
}

public static int sumOfNums(List<Integer> lstNums){
   System.out.println("Sum invoked");
   return lstNums.stream().mapToInt(num -> num).sum();
}

Output

Sum invoked

Using mono.fromSupplier would invoke the sumOfNums during Terminal Operation rather than Intermediate Operation

List<Integer> lstNums = List.of(1,2,3);
        Mono.fromSupplier(() -> sumOfNums(lstNums)); // Intermediate Operation                 


  public static int sumOfNums(List<Integer> lstNums){
        System.out.println("Sum invoked");
        return lstNums.stream().mapToInt(num -> num).sum();
  }

Output


Mono.fromSupplier vs Mono.fromCallable
fromCallable calls a checked exception where as fromSupplier doesnot throws checked exception. So if you substitute supplier in place of callable you should also write try catch block to handle exception

We use property binding to pass value from component to form element in html and event binding to pass value from html to angular component.

  1. In the below code when we use [value] to get the value from component to html
  2. The same way we use (input) to get back value on event like change of name text
  3. {{employee.Name}} is used to display the value. You can remove [value] or (input) to check the behavior.
  4. Instead of this we can use ngModule by importing FormsModule which takes care of both propery and data binding

empform.html

<form>
<input type="text" [value]="employee.Name" (input)="employee.Name=$event.target.value" />
{{employee.Name}}
</form>

EmployeeModel.ts

export class Employee {
  private _Name: String;

  constructor(name: String) {
    this._Name = name;
  }
}

EmployeeController.ts

export class AddemployeeComponent implements OnInit {
.
.
  public employee: Employee;

  constructor() {
    this.employee = new Employee('Mugilvannan');
  }
.
.
}

  1. For NgModeul to work name attribute(i.e. employeeName) is mandatory in form field.
    Otherwise the value wont be reflected on change
  2. [ngModel] is for value binding and (ngModelChange) is for event binding. Both can be grouped in to format called banana-in-a-box. [(ngModel)]
  3. For using ngModel, FormsModule should be added to app.module.ts
  4. So when to use expanded syntax of ngModel. There would be times where you want to change the text into uppercase or lowercase once it is entered into textbox or formfields. In suchcase we should call an event which does it. At that time you would use (ngModelChange) instead of [(ngModel)].

addemployee.component.html

  <form>
    <table style="border-collapse:collapse;" border="1" cellpadding="5">
      <tbody>
        <tr>
          <td>Name</td>
          <td><input type="text" name="employeeName" [ngModel]="employee.Name" (ngModelChange)="employee.Name=$event" /></td>
        </tr>
        <tr>
          <td colspan="2">
            <input type="submit" value="Add Employee" (click)="employee.Name='test'" />
          </td>
        </tr>
      </tbody>
    </table>
  </form>
  {{employee.Name}}

addemployee.component.html – Banana-in-a-Box format

.
.
<td><input type="text" name="employeeName" [(ngModel)]="employee.Name"/></td>
.
.

Modules helps in writing clean code like seperating modules for dataacces, UI and security. Each modules has a separate role of its own
like httpModule, routing module. Writing Modules in TS would create IIFE(Immediately Invoked Function Expression) in javascript file

module dataService{

}

So what is difference between class and module. Both are same except one. Classes are created in Global namespace.
However module can be either global or local.

class dataService{

}

Now lets wrap class with in module which is nothing more than namespace

module Shapes{
  export class Rectangle{

  } 

  export class Square{

  } 

  export class Triangle{

  } 
}

var objShapes:any = new Shapes.Square;

Simple Program for Logging Message using Module and Interface

interface ILoggerUtils {
    print(): void;
}

var LogLevel = {
    info: 1,
    Warn: 2,
    Error:3
}

module LogUtils {
    export class LoggerAtError implements ILoggerUtils {
        
    print(): void {
        console.log("Log Message during Error");
    }
}

export class LoggerAtInfo implements ILoggerUtils {
    print(): void {
        console.log("Log Message during Info");
    }
}

export class LoggerAtWarn implements ILoggerUtils {
    print(): void {
        console.log("Log Message during Warn");
    }
  }
}

window.onload = function () {
    var objLoggerUtil: ILoggerUtils;

    var logLevel = LogLevel.info;

    switch (logLevel) {
        case LogLevel.info:
            objLoggerUtil = new LogUtils.LoggerAtInfo();
            break;
        case LogLevel.Warn:
            objLoggerUtil = new LogUtils.LoggerAtWarn();
            break;
        case LogLevel.Error:
            objLoggerUtil = new LogUtils.LoggerAtError();
            break;
    }

    objLoggerUtil.print();
}

Output

Log Message during Info

While doing we need to let know Typescript how the datatypes are defined.The definition files are available in internet and it should be added to the script folder while doing the casting

Suppose I am doing a casting HTMLElement while accessing DOMto HTMLInputElement i should add lib.d.ts which contains the definition for DOM elements.

In the below code document.getElementById(‘Name’) returns HTMLElement which is least specific compared to HTMLInputElement.

var name = <HTMLInputElement>document.getElementById('Name');
  1. Using Interface we can have blue print of list of things which needs to be implemented
interface calculateInterest {
    accountType: String,
    interest: number,
    depAmt?: number,
    calculateInt(depositAmt: number) : number;
} 

var IntForSavings: calculateInterest = {
    accountType: "Savings",
    interest: 12,     
    depAmt : 0,
    calculateInt: function (depositAmt:number) {
        this.depAmt = depositAmt;
        return depositAmt * this.interest;
    }    
};

var IntForCurrent: calculateInterest = {
    accountType: "Current",
    interest: 5,           
    depAmt: 0,
    calculateInt: function (depositAmt: number) {
        this.depAmt = depositAmt;
        return depositAmt * this.interest;
    }
};

var IntForLoans: calculateInterest = {
    accountType: "Loan Account",
    interest: 8,
    depAmt: 0,
    calculateInt: function (depositAmt: number) {
        this.depAmt = depositAmt;
        return depositAmt * this.interest;
    }
};

console.log(IntForSavings.accountType + ' yields ' + IntForSavings.calculateInt(12000) + ' for cash amount of ' + IntForSavings.depAmt);
console.log(IntForCurrent.accountType + ' yields ' + IntForCurrent.calculateInt(6000) + ' for cash amount of ' + IntForCurrent.depAmt);
console.log(IntForLoans.accountType + ' yields ' + IntForLoans.calculateInt(3000) + ' for cash amount of ' + IntForLoans.depAmt);

Output

Savings yields 144000 for cash amount of 12000
Current yields 30000 for cash amount of 6000
Loan Account yields 24000 for cash amount of 3000

Classes extending Interface
Accounts.ts

interface Accounts {
    accountType?: string;
    calculateInterest(accountType: string): number;
}

class SavingsAcc implements Accounts {
   
    minimumBalance: number = 10000;
    accountType: string = 'Savings';    

    calculateInterest(accountType: string): number{
        return 5;
    }
}

class CurrentAcc implements Accounts {
    minimumBalance: number;
    accountType: string = 'Current';
    calculateInterest(accountType: string): number {
        return 5;
    }
}

class LoanAcc implements Accounts {
    accountType: string = 'Loan';
    calculateInterest(accountType: string): number {
        return 12;
    }
}

class Customer {
    private _accountType: Accounts;          

    constructor(customerId: number, AccountType : Accounts) {
        this._accountType = AccountType;
    }

    public get accountType(): Accounts {
        return this._accountType;
    }
    public set accountType(value: Accounts) {
        this._accountType = value;
    }
}

window.onload = function () {
    var objCustomer: Customer = new Customer(1001, new LoanAcc());    
    console.log(objCustomer.accountType.accountType + ' Account with interest rate of ' + objCustomer.accountType.calculateInterest('Loan'));


    var objCustomer: Customer = new Customer(1001, new SavingsAcc());
    console.log(objCustomer.accountType.accountType + ' Account with interest rate of ' + objCustomer.accountType.calculateInterest('Savings'));
}

Output

Loan Account with interest of 12
Savings Account with interest of 5

Accessing property of class extending Interface
We have the same code of Accounts.ts with slight modification on window.load. We try to access a property specific to class implementing interface.
In the below code minimumBalance is a property specific to savingsAccount which implements Accounts. In such case we need to do type case from generic interface object to specific class object
so the property specific to class is available.

window.onload = function () {
    var objCustomer: Customer = new Customer(1001, new SavingsAcc());
    var objSavingAcc: SavingsAcc = <SavingsAcc>objCustomer.accountType;
    console.log(objCustomer.accountType.accountType + ' Account with interest rate of ' + objCustomer.accountType.calculateInterest('Savings') + ' with minimum balance of ' + objSavingAcc.minimumBalance);
}

Output

Savings Account with interest rate of 5 with minimum balance of 10000

Using Interface to write clean code
One of the advantage of interface is while passing multiple arguments to constructor we can avoid the misplacement of the argument passed
like the one in code below. This is similar to ENUM in Java. The the Account class constructor we can change the arguments to interface as follows

Interfaces.ts

interface IPerson {
    name: string;
    age: number;
    location: string;
}

interface IEmployee extends IPerson{
    empId: number;
}

interface ICustomer extends IPerson {
    custId: number;
    accType: string;
}

Account.ts

class Account {
    private _name: string;
    private _age: number;
    private _location: string;    
    private _custId: number;   
    private _accType: string;   

    constructor(name: string, age: number, location: string, custId: number, accType: string) {    
        this._name = name;
        this._age = age;
        this._location = location;
        this._custId = custId;
        this._accType = accType;
    }
}

Refactored Account class with constructor arguments changed to inteface

Account.ts

class Account {
    private _name: string;
    private _age: number;
    private _location: string;    
    private _custId: number;   
    private _accType: string;   

    constructor(iPerson: ICustomer) {
        this._name = iPerson.name;
        this._age = iPerson.age;
        this._location = iPerson.location;
        this._custId = iPerson.custId;
        this._accType = iPerson.accType;
    }
}

Functions using arrow function Expression

var multiply = function (num: number) {
        return num * num;
}

The same above function could be written using arrow key expression as below

var multiply = (num1: number, num2: number) => return num1 * num2;

//With flower braces in case of multiple statements
var multiply = (num1: number, num2: number) => {return num1 * num2;};

we can also do function declaration and definition in two separate lines as one below

//function declaration
var multiply: (num1: number, num2: number) => number;    

//function definition
multiply = function (num1: number, num2: number) {
  return num1 * num2;
}

//function taking object literals as arguments
var multiply: (numbs: { num1: number, num2: number }) => number;    
var numbs = { num1: 2, num2: 4 };

multiply = function (numbs) {
   return numbs.num1 * numbs.num2;
}
  1. What is difference between let and var while declaring variable?
    var is Function Scoped and let is block scoped
    Using var

    var foo = 123;
    if (true) {
        var foo = 456;
    }
    
    console.log(foo); // 456
    

    Using let

    let foo = 123;
    if (true) {
        let foo = 456;
    
    }
    console.log(foo); // 123
    
  2. What would be the value of the below variables?
     
     //Value is Undefined
     var foo:string;
     
     //You can explicitly define value as undefined 
     var age = undefined;
    
     //any is a valid value which is default type until the variable assumes some data type by type inference
     var location:any;
    
     //undefined and null could be assigned to any of the datatype
     var pincode:any=undefined;
     var state:any=null;
    
  3. Why the below is not possible in interface?
    I am having a interface and class like one below which results in compile time exception

    interface test1 {
    }
    
    class test2 implements test1
    {
        public foo;
    }
    
    let test: test1 = new test2();
    
    test.foo = 'test';
    

    The reason for the compilation error is when you reference a variable with specific interface in TypeScript, you can only use the properties and methods declared in the interface of the variable
    You are assigning test1 as a type of test variable, test1 interface doesn’t have foo property in it. so that’s why you are getting this error. If you change the type to let test: test2: new test2();. it won’t throw any error like one below

    let test: test2 = new test2();
    test.foo = 'test';
    

    There are two workaround for this. One is not to define the type while initializing variable like one below

    interface test1 { }
    class test2 implements test1{
        public foo;
    }
    let test = new test2();
    test.foo = 'test';
    

    Other is to use any while initializing variable

    interface test1 { }
    class test2 implements test1{
        public foo;
    }
    let test: test1 | any = new test2();
    test.foo = 'test';
    
  1. Services are mostly used in displaying datas from APIs
  2. To generate a new service use ng generate service Services/SERVICE_NAME
  3. services are injectable because they would be mostly called by other components
  4. Injection of services can happen at three level
    • AppModule – Same Instance of Service Injected would be available across application
    • AppComponent – Same Instance of Service Injected at this level would be available in this component and all child component
    • Any Other Component – Same Instance of Service Injected would be available to this component and child component(not to parent component)
  5. @Injectable is not needed if the Service is added in app.modules.ts

aboutus.component.ts

.
.
constructor(private objApi:ApiService) { 
    this.objApi.getDataFromRest();
  }
.
.

api.service.ts

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

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

  constructor() { }

  getDataFromRest()
  {
    return console.log("Data from Rest Method");
  }
}

If Else
aboutus.component.ts

export class AboutusComponent implements OnInit {
  showMsg: boolean = true;
  .
  .
  .
}

aboutus.component.html

<p *ngIf='showMsg; else elseBlock'>aboutus works from If block!</p>

<ng-template #elseBlock>
    <p>aboutus works from else block!</p>
</ng-template>

Output

aboutus works from If block!

Switch Case
aboutus.component.ts

export class AboutusComponent implements OnInit {
  .
  .
  color : string =  'pink';
  .
  .
}

aboutus.component.html

<div [ngSwitch] = 'color'>
    <p *ngSwitchCase="'blue'">Its Blue Color</p>
    <p *ngSwitchCase="'red'">Its Red Color</p>
    <p *ngSwitchCase="'green'">Its Green Color</p>    
    <p *ngSwitchDefault>Its Default Color</p>    
</div>

Output

Its Default Color