-1

I have a question for about Angular Project (v.10.2.5). I wanna set some event behaviors for HttpClient (for example I wanna show full screen loading indicator for all http methods, also I wanna write log to console). I have so many api methods and I using nswag. Does Angular have such a feature? (example: .Net Core able to create customized HttpClient templates in Program.cs). Thank you..

I'm a new guy in Angular :) I'm googling but don't find anything. So, I couldn't something..

1 Answers1

0

Yes! and it doesn't require a third part library either. One can subscribe to that service can be imported to any component send an alert notification. I also inject a loaded class and fade in, which is included now.

It's when I first started I wished someone would have shown me, so I extend this courtesy to you.

This is my default loader for all applications.
app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {HttpClientModule} from '@angular/common/http'

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

import { Component } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
import { Subscription, merge, of, fromEvent, map } from 'rxjs';
import { NotifyViewService } from './common/services/notify-view.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'YOURAPPNAMEHERE';
  constructor(private router: Router, private notify: NotifyViewService) {

  }
  internetstate$: Subscription = Subscription.EMPTY;

  ngOnInit() {
    //const html ref
    const htmlEl = document.getElementById('root') as HTMLElement;
    // element ref loader
    const loadingEl = document.getElementById('loader') as HTMLElement;
    // element ref content
    const contentEl = document.getElementById('content') as HTMLElement;
    // this.offlineEventCheck();
    // this.offlineNavigatorCheck();
    // subscribe to router to get events
    this.router.events.subscribe((events)=>{
      // listen for navigation started then remove the none class from loader element
      if(events instanceof NavigationStart){
        loadingEl?.classList.remove('loaded');
      }
      // listen for navigation end 
      if(events instanceof NavigationEnd){
        // add 1.5 second delay to see the loader and allow time for content to load
        setTimeout(()=>{
          // add the none class to hide the loader element
          loadingEl?.classList.add('none');
          // remove the none class to show the content element router-outlet
          contentEl.classList.add("fadeIn");
          contentEl?.classList.remove('none');
         
        }, 1500)
      
      }
    })
    // check to see if the internet is connected
    this.internetState();

  }
  ngOnChanges(){
    // if there are changes - just run the internet state
    // currently will not fire without changes/simple changes
    this.internetState()
  }
  ngOnDestroy() {
    // unsubcribe from ther internet state
    this.internetstate$.unsubscribe()
  }
  internetState() {
    // this.internetstate = navigator.onLine;
    // listen for fromEvent window to get state
    // pipe and map the navigator online boolean
    // subcribe to the boolean and toggle the slass
    // then set a notification - if its online it will be ignored programatically
    // must exact match true - could be toggled on boolean I didnt set false or true
    this.internetstate$ = merge( of (null),
        fromEvent(window, 'online'),
        fromEvent(window, 'offline')
      )
      .pipe(map(() => navigator.onLine))
      .subscribe(state => {
        // console lof the state remove or rem out before production
        console.log('state', state);
        // if internet is true its online
        if(state===true){
          const message = {
            name: "online",
            message:""
          }
          // send notify alert with online name
          this.notify.setNotify(message)
          
        }
        // if internet is false its offline
        if(state===false){
          // console.log false remove or rem out before production
          console.log('false')
          // set a 200 millisecond timeout to allow the notification to receive the message constant
          setTimeout(()=>{
            const message = {
              name: "offline",
           message: "this application requires internet connectivity"
          }
          // send the message constant
          this.notify.setNotify(message)
          },200)
        }
      });
  }

app.component.css

.none{
    display: none !important;
    height: 0 !important;
}

app.component.html

<div class="loaded" id="loader">
  <div id="ctn-preloader" class="ctn-preloader">
      <div class="animation-preloader">
          <div class="spinner"></div>
          <div class="txt-loading">
              <span data-text-preloader="L" class="letters-loading">
                  L
              </span>
              
              <span data-text-preloader="O" class="letters-loading">
                  O
              </span>
              
              <span data-text-preloader="A" class="letters-loading">
                  A
              </span>
              
              <span data-text-preloader="D" class="letters-loading">
                  D
              </span>
              
              <span data-text-preloader="I" class="letters-loading">
                  I
              </span>
              
              <span data-text-preloader="N" class="letters-loading">
                  N
              </span>
              
              <span data-text-preloader="G" class="letters-loading">
                  G
              </span>
          </div>
      </div>    

      <div class="loader-section section-left"></div>
      <div class="loader-section section-right"></div>
  </div>
</div>

<!-- content outlet -->
<div class="none" id="content">
  <router-outlet></router-outlet>
</div>

index.html

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>YOURAPPNAMEHERE</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500&display=swap" rel="stylesheet">
</head>
    <body id="body">
      <!-- style is the fix for angular smooth scroll events -->
      <style>
        body{
          margin:0;
          padding:0;
          scroll-behavior: smooth !important;
        }
        </style>
      <app-root></app-root>
    </body>
</html>

**services/notify.service.ts **

  import { Injectable } from '@angular/core';
    import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
    interface NotifyI {
      name: string;
      message: string;
      stack?: string;
    }
    @Injectable({
      providedIn: 'root'
    })
    export class NotifyViewService {
      private viewportnotifySubject = new BehaviorSubject({} as NotifyI);
      public viewportnotifyObserver = this.viewportnotifySubject.asObservable();
      private shownotifySubject = new BehaviorSubject(false);
      public shownotifyObserver = this.shownotifySubject.asObservable();
      constructor() { }
      setNotify(message:NotifyI){
        this.viewportnotifySubject.next(message);
        this.shownotifySubject.next(true);
      }
      clearNotify(){
        const clear:NotifyI={
          name: null as unknown as string,
          message: null as unknown as string,
          stack: null as unknown as string
        }
        this.viewportnotifySubject.next(clear as any as NotifyI);
        this.shownotifySubject.next(false)
      }
    }

style.css

:root {
    --primary-color: #222222;
    --secondary-color: #d72323;
    --yellow-color: #ffc107;
    --text-gray-color: #4a4c59;
    --white-color: #ffffff;
    --ofwhite-color: #e6e6e6;
    --black-color: #000000;
    --light-color: #a5a5a5;
    --light-color2: #aaaaaa;
    --dark-color: #242424;
    --sky-color: #647589;
    --border-color: #e4e4e4;
    --border-color2: #e4e4e4;
    --border-color3: #dddddd;
    --border-dark: #383434;
    --bg-gray-color: #f7f8fc;
    --gray-color: #ebebeb;
    --gray-color2: #f5f5f5;
    --rubik: "Rubik", sans-serif;
    --work-sans: "Work Sans", sans-serif;
    --roboto:"Roboto", sans-serif;
    --body-font-size: 1.7rem;
    --body-font-weight: 400;
    --body-line-height: 2.6rem;
    --headings-weight: 700;
    --transition: all 0.3s ease 0s;
    --container-fluid-offset: 16rem;
  }
  
  /* 
      28. Preloader css 
  */
  .ctn-preloader {
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    height: 100%;
    -webkit-box-pack: center;
    -ms-flex-pack: center;
    justify-content: center;
    position: fixed;
    left: 0;
    top: 0;
    width: 100%;
    z-index: 9999;
    pointer-events: none;
  }
  
  .ctn-preloader .animation-preloader {
    position: absolute;
    z-index: 100;
  }
  
  .ctn-preloader .animation-preloader .spinner {
    -webkit-animation: spinner 1s infinite linear;
    animation: spinner 1s infinite linear;
    border-radius: 50%;
    border: 4px solid var(--light-color2);
    border-top-color: var(--black-color);
    height: 9em;
    margin: 0 auto 3.5em auto;
    width: 9em;
  }
  
  .ctn-preloader .animation-preloader .txt-loading {
    font-weight: 900;
    text-align: center;
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    font-family:var(--roboto);
    color: var(--md-ref-palette-primary90);
    font-size: 3.5rem;
  }
  
  .ctn-preloader .animation-preloader .txt-loading .letters-loading:before {
    animation: letters-loading 5s infinite;
    color: var(--md-ref-palette-primary90);
    content: attr(data-text-preloader);
    left: 0;
    opacity: 0;
    position: absolute;
    top: 0;
    -webkit-transform: rotateY(-90deg);
    transform: rotateY(-90deg);
    -webkit-animation: letters-loading 5s infinite;
  }
  
  .ctn-preloader .animation-preloader .txt-loading .letters-loading {
    color: rgba(233, 233, 233, 0.2);
    position: relative;
  }
  
  .ctn-preloader
    .animation-preloader
    .txt-loading
    .letters-loading:nth-child(2):before {
    -webkit-animation-delay: 0.2s;
    animation-delay: 0.2s;
  }
  
  .ctn-preloader
    .animation-preloader
    .txt-loading
    .letters-loading:nth-child(3):before {
    -webkit-animation-delay: 0.3s;
    animation-delay: 0.3s;
  }
  
  .ctn-preloader
    .animation-preloader
    .txt-loading
    .letters-loading:nth-child(4):before {
    -webkit-animation-delay: 0.4s;
    animation-delay: 0.4s;
  }
  
  .ctn-preloader
    .animation-preloader
    .txt-loading
    .letters-loading:nth-child(5):before {
    -webkit-animation-delay: 0.5s;
    animation-delay: 0.5s;
  }
  
  .ctn-preloader
    .animation-preloader
    .txt-loading
    .letters-loading:nth-child(6):before {
    -webkit-animation-delay: 0.6s;
    animation-delay: 0.6s;
  }
  
  .ctn-preloader
    .animation-preloader
    .txt-loading
    .letters-loading:nth-child(7):before {
    -webkit-animation-delay: 0.7s;
    animation-delay: 0.7s;
  }
  
  .ctn-preloader .loader-section {
    background: var(--md-ref-palette-primary30);
    height: 100%;
    position: fixed;
    top: 0;
    width: calc(50% + 1px);
  }
  
  .ctn-preloader .loader-section.section-left {
    left: 0;
  }
  
  .ctn-preloader .loader-section.section-right {
    right: 0;
  }
  
  .loaded .animation-preloader {
    opacity: 0;
    transition: 0.5s ease-out;
    -webkit-transition: 0.5s ease-out;
    -moz-transition: 0.5s ease-out;
    -ms-transition: 0.5s ease-out;
    -o-transition: 0.5s ease-out;
  }
  
  .loaded .loader-section.section-left {
    -webkit-transition: 0.7s 0.3s all cubic-bezier(0.1, 0.1, 0.1, 1);
    transition: 0.7s 0.3s all cubic-bezier(0.1, 0.1, 0.1, 1);
    -webkit-transform: translateX(-101%);
    transform: translateX(-101%);
  }
  
  .loaded .loader-section.section-right {
    -webkit-transition: 0.7s 0.3s all cubic-bezier(0.1, 0.1, 0.1, 1);
    transition: 0.7s 0.3s all cubic-bezier(0.1, 0.1, 0.1, 1);
    -webkit-transform: translateX(101%);
    transform: translateX(101%);
  }
  
  /* Animación del preloader */
  @-webkit-keyframes spinner {
    to {
      -webkit-transform: rotateZ(360deg);
      transform: rotateZ(360deg);
    }
  }
  @keyframes spinner {
    to {
      -webkit-transform: rotateZ(360deg);
      transform: rotateZ(360deg);
    }
  }
  
  /* Animación de las letras cargando del preloader */
  @-webkit-keyframes letters-loading {
    0%,
    75%,
    100% {
      opacity: 0;
      -webkit-transform: rotateY(-90deg);
      transform: rotateY(-90deg);
    }
    25%,
    50% {
      opacity: 1;
      -webkit-transform: rotateY(0deg);
      transform: rotateY(0deg);
    }
  }
  @keyframes letters-loading {
    0%,
    75%,
    100% {
      opacity: 0;
      -webkit-transform: rotateY(-90deg);
      transform: rotateY(-90deg);
    }
    25%,
    50% {
      opacity: 1;
      -webkit-transform: rotateY(0deg);
      transform: rotateY(0deg);
    }
  }
  
  /*# sourceMappingURL=style.css.map */
  
  /* fadeIn */
  @-webkit-keyframes fadeIn {
      0% {
        opacity: 0; }
      100% {
        opacity: 1; } }
    @-moz-keyframes fadeIn {
      0% {
        opacity: 0; }
      100% {
        opacity: 1; } }
    @-o-keyframes fadeIn {
      0% {
        opacity: 0; }
      100% {
        opacity: 1; } }
    @keyframes fadeIn {
      0% {
        opacity: 0; }
      100% {
        opacity: 1; } }
    
    .fadeIn {
      -webkit-animation: fadeIn .25s ease-in;
      -moz-animation: fadeIn .25s ease-in;
      -o-animation: fadeIn .25s ease-in;
      animation: fadeIn .25s ease-in; }
    
  
  html, body { height: 100%; }
  body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
  i {
    color: #222222
  }
  

terminal or command line:

npm install bootstrap then import the min and icons as a font.
npm install bootstrap-icons

edit angular.json to use bootstrap.

"styles": [
              "node_modules/bootstrap/dist/css/bootstrap.min.css",
              "node_modules/bootstrap-icons/font/bootstrap-icons.css",
              "src/styles.css"
            ],
            "scripts": [
              "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"
            ]