Search code examples
angularchatbot

How to persist a component across all screens in Angular 7?


I'm trying to persist the chat-bot component across all screens in my Angular project. I tried to refer the component's selector in app.component.html like the below code

<app-navbar></app-navbar>
<section>
  <router-outlet></router-outlet>
</section>
<app-chat-popup></app-chat-popup>
<app-footer></app-footer>

But it is not linking the component as expected. If I refer as a normal component that gets triggered on a button click then it is working as expected. But I need it to be in all the screens in my project. Any help would be appreciated. Thanks!

Edit: This is my Chat component HTML file

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  </head>
  <body>
    <!-- Message box -->
    <div class="chat_box">
      <div class="chat_header">
        <!-- <img src="user.jpg" class="user_icon" /> -->
        <h4 class="username">Virtual agent</h4>
        <i class="fas fa-times close"></i>
      </div>
      <hr />
      <div *ngIf="chatVisible" class="message_content">
          <ng-container #messageList *ngFor="let message of messages | async">

              <div class="message" [ngClass]="{ 'from': message.sentBy === 'bot',
                                                'to':   message.sentBy === 'user' }">
                {{ message.content }}
              </div>

            </ng-container>
      </div>
      <div class="input_box">
        <input [(ngModel)]="formValue" (keyup.enter)="sendMessage()" placeholder="Your message here..." type="text">
        <button (click)="sendMessage()">se</button>
        <i class="fas fa-location-arrow"></i>
      </div>
    </div>
  </body>
</html>

Solution

  • I've done something similar to this using @ViewChild for a modal that appears on every page of a website using ngx-bootstrap. If your chatbot window can be assigned to a modal, this should work fine. I'm using Angular 8 btw.

    You just need to import your modal module into your root component as a typical component, and leave your index.html the way it is, separately referencing the modal component outside of your routing component.

    import { ModalDirective } from 'ngx-bootstrap/modal';
    import { Component, OnInit, ViewChild } from '@angular/core';
    export class LoginBannerComponent implements OnInit {
    
    constructor() {}
    
    ngOnInit() {
    }
    
    @ViewChild('autoShownModal', { static: false })
    autoShownModal: ModalDirective;
    isModalShown = true;
    
    showModal(): void {
        this.isModalShown = true;
    }
    
    hideModal(): void {
        this.autoShownModal.hide();
    }
    
    onHidden(): void {
        this.isModalShown = false;
    }
    accept(): void {
        this.autoShownModal.hide();
    }
    
    reject(): void {
        this.isChildModalShown = true;
        this.isModalShown = false;
    
    }
    

    And my HTML template:

    <div #autoShownModal="bs-modal"
     (onHidden)="onHidden()"
     *ngIf="isModalShown"
     [config]="{ show: true, animated: true, backdrop: true, ignoreBackdropClick: true }"
     aria-labelledby="dialog-auto-name"
     bsModal
     class="fade modal"
     role="dialog"
     tabindex="-1">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-body text-white"
                 style="background-color: #0072CE">
                <p class="font-weight-bold h4 text-capitalize text-center">MODAL CONTENT HERE</p>
                <div class="modal-footer text-white">
                    <button (click)="accept()"
                            class="btn btn-success mr-auto"
                            type="button">
                        Accept
                    </button>
                    <button (click)="reject()"
                            class="btn btn-danger"
                            type="button">
                        Reject
                    </button>
                </div>
            </div>
        </div>
    </div>
    

    You can use libraries like moment.js and angular local storage to only display modals based on amounts of time since page has been visited, etc.