How To Create Chat Application Using SignalR In Angular?

In this article, we will learn how to crate chat application using signalR in angular.

Introduction:

We now require a real-time connection to retrieve information or data from a server. As a result, SignalR provides these features for data transmission from a server for real-time applications.

SignalR:

SignalR is open-source real-time framework with high performance.

SignalR provides a simple API for establishing server-to-client  remote procedure calls(RPC) that call JavaScript functions in client browsers from server-side.NET code.

SignalR additionally contains API for connection management and connection grouping.

It is easy to integrate many application using SignalR.

Now, Let’s create first ASP.NET core web API

1)  Create .NET Core web API using Microsoft visual studio.

Assign the appropriate name to the project.

Now, create new folder named enitites in that we need to create User & message class to create table in database.

Next we have to add DbContext class to add migration in database.

Add the following packages which we need to create chat app from the Nuget Package Console.

Users.cs

using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;

namespace Chat_Application.Entities
{
    public class Users : IdentityUser
    {
        [Column(TypeName = "nvarchar(150)")]
        public string FirstName { get; set; }

        [Column(TypeName = "nvarchar(150)")]
        public string LastName { get; set; }

        public bool IsOnline { get; set; }
        public string Theme { get; set; }
        public string color { get; set; }
    }
}

we need to implement IdentityUser interface to access inbuilt user properties.

Here, we also create theme & color field to change the theme as user want.

Message.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace Chat_Application.Entities
{
    public class Message
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public string Id { get; set; }
        public string Sender { get; set; }
        public string Receiver { get; set; }
        public DateTime MessageDate { get; set; }
        public string Content { get; set; }

        public bool IsNew { get; set; }


        public bool IsSenderDeleted { get; set; }


        public bool IsReceiverDeleted { get; set; }
    }
}

Now add Dbcontext class to create migration.

SimplechatDbContext.cs

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;

namespace Chat_Application.Entities
{
    public class SimpleChatDbContext : IdentityDbContext
    {
        public SimpleChatDbContext(DbContextOptions options) : base(options)
        {

        }
        public DbSet<Users> User { get; set; }

        public DbSet<Message> Message { get; set; }
    }
}

We need to register service in the startup.cs file .

namespace Chat_Application
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<ApplicationSetting>(Configuration.GetSection("ApplicationSettings"));
            services.AddDbContext<SimpleChatDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("SimpleChatConnectionString")));

            services.AddIdentity<Users, IdentityRole>().AddEntityFrameworkStores<SimpleChatDbContext>();
       
            services.Configure<IdentityOptions>(options =>
            {
                options.Password.RequireDigit = false;
                options.Password.RequireNonAlphanumeric = false;
                options.Password.RequireLowercase = false;
                options.Password.RequireUppercase = false;
                options.Password.RequiredLength = 4;
            }
            );
           
            services.AddCors();
            
           
            services.AddSignalR();

            services.AddControllers();
            
            services.AddOptions();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "Chat_Application", Version = "v1" });
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Chat_Application v1"));
            }

             app.UseHttpsRedirection();
           
            app.UseRouting();
            app.UseCors(builder =>
            builder.WithOrigins("http://localhost:4200")
            .AllowAnyHeader()
            .AllowAnyMethod()
            .AllowCredentials()

            );

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
               
            });
        }
    }
}

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "SimpleChatConnectionString": "Server=your server name; database=database name; User Id= your userId; Password= your password;"
  },
 "ApplicationSettings": {
"JWT_Secret": "1234567890123456",
"Client_URL": "http://localhost:4200/"
}

}

Next, open the package Manager Console from the Tool menu.

write a below command in the console.

Add-migration Initial

This command create migration folder in our .NET core application with .cs file which have fields information of the table which are going to be created in the database.

Now write following command

update-database

It will create table which is mentioned in DbContext class.

create MessageService class with its interface.

IMessageservice.cs

namespace Chat_Application.Interface
{
    public interface IMessageService
    {
        void Add(Message message);
       
    }
}

Messageservice.cs

namespace Chat_Application.Interface
{
    public class MessageService : IMessageService
    {
        protected SimpleChatDbContext Context;
        public MessageService(SimpleChatDbContext context)
        {
            Context = context;
        }
       
        public void Add(Message message)
        {
            Context.Message.Add(message);
            Context.SaveChanges();
        }
    }
}

Now, create new folder named Hubs inside that create chatHub class to initialize connection with signalR.

Next we create new folder named Model inside that create loginModel & ApplicationUserModel to loging and register new user in the application.

LoginModel.cs

public class LoginModel
    {
        public string Email { get; set; }
        public string password { get; set; }
    }

ApplicationUserModel.cs

public class ApplicationUserModel
    {
        public string Id { get; set; }
        public string UserName { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public string FirstName { get; set; }

        public string LastName { get; set; }
        public bool IsOnline { get; set; } = false;
        public string Role { get; set; }
        public string Theme { get; set; }
        public string color { get; set; }
        
    }

ChatHub.cs

using Chat_Application.Entities;
using Chat_Application.Interface;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Chat_Application.Hubs
{
    public class ChatHub : Hub
    {
        private readonly IMessageService messageService;
        public ChatHub(IMessageService messageService)
        {
            this.messageService = messageService;
        }
        static IList<UserConnection> Users = new List<UserConnection>();

        public class UserConnection
        {
            public string UserId { get; set; }
            public string ConnectionId { get; set; }
            public string ConnectionId { get; set; }
            public string FullName { get; set; }
            public string Username { get; set; }
        }
        public Task SendMessageToUser(Message message)
        {
            var reciever = Users.FirstOrDefault(x => x.UserId == message.Receiver);
            var connectionId = reciever == null ? "offlineUser" : reciever.ConnectionId;
            this.messageService.Add(message);
            return Clients.Client(connectionId).SendAsync("ReceiveDM", Context.ConnectionId, message);
        }
        public async Task PublishUserOnConnect(string id, string fullname, string username)
        {

            var existingUser = Users.FirstOrDefault(x => x.Username == username);
            var indexExistingUser = Users.IndexOf(existingUser);

            UserConnection user = new UserConnection
            {
                UserId = id,
                ConnectionId = Context.ConnectionId,
                FullName = fullname,
                Username = username
            };

            if (!Users.Contains(existingUser))
            {
                Users.Add(user);

            }
            else
            {
                Users[indexExistingUser] = user;
            }

            await Clients.All.SendAsync("BroadcastUserOnConnect", Users);

        }
        public void RemoveOnlineUser(string userID)
        {
            var user = Users.Where(x => x.UserId == userID).ToList();
            foreach (UserConnection i in user)
                Users.Remove(i);

            Clients.All.SendAsync("BroadcastUserOnDisconnect", Users);
        }
    }
}

Now, right click on controller folder and add Account Controller. And copy the following code & paste it.

AccountController.cs

using Chat_Application.AppSetting;
using Chat_Application.Entities;
using Chat_Application.Model;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.IO;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace Chat_Application.Controllers
{
    [Route("api/account")]
    [ApiController]
    public class AccountController : ControllerBase
    {
        private UserManager<Users> userManager;
        private readonly ApplicationSetting appSettings;
        const string key = "E546C8DF278CD5931069B522E695D4F2";

        public AccountController(UserManager<Users> userManager, IOptions<ApplicationSetting> appSettings)
        {
            this.userManager = userManager;
            this.appSettings = appSettings.Value;
        }


        [HttpGet]
        public IActionResult GetAll()
        {
            var result = this.userManager.Users.ToList();
            return Ok(result);
        }

        [HttpPost]
        [Route("Register")]
        //POST : /api/User/Register
        public async Task<Object> Register(ApplicationUserModel model)
        {

            var applicationUser = new Users()
            {
                UserName = model.Email,
                Email = model.Email,
                FirstName = model.FirstName,
                LastName = model.LastName,
                PasswordHash = EncryptString(model.Password, key)
            };


            try
            {
                var result = await this.userManager.CreateAsync(applicationUser);
                return Ok(result);
            }
            catch (Exception ex)
            {

                throw ex;
            }
        }
        [HttpPost]
        [Route("Login")]
        public async Task<IActionResult> Login(LoginModel model)
        {
            var user = await this.userManager.FindByNameAsync(model.Email); 
            if (user != null)
            {
                var decryptPassword = DecryptString(user.PasswordHash, key);
                if (decryptPassword != model.password)
                {
                    return BadRequest(new { message = "Username or password is incorrect." });
                }

                try
                {

                    IdentityOptions _options = new IdentityOptions();
                    var tokenDescriptor = new SecurityTokenDescriptor
                    {
                        Subject = new ClaimsIdentity(new Claim[]
                        {
                        new Claim("UserID",user.Id.ToString()),
                        new Claim("UserName",user.UserName),
                        new Claim("FullName",user.FirstName+" "+user.LastName),
                        }),
                        Expires = DateTime.UtcNow.AddDays(1),
                        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.appSettings.JWT_Secret)), SecurityAlgorithms.HmacSha256Signature)
                    };
                    var tokenHandler = new JwtSecurityTokenHandler();
                    var securityToken = tokenHandler.CreateToken(tokenDescriptor);
                    var token = tokenHandler.WriteToken(securityToken);
                    user.IsOnline = true;
                    return Ok(new { token, user });
                }
                catch (Exception exp)
                {
                    throw;
                }
            }
            else
                return BadRequest(new { message = "Username or password is incorrect." });
        }
        public static string EncryptString(string text, string keyString)
        {
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var encryptor = aesAlg.CreateEncryptor(key, aesAlg.IV))
                {
                    using (var msEncrypt = new MemoryStream())
                    {
                        using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                        using (var swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(text);
                        }

                        var iv = aesAlg.IV;

                        var decryptedContent = msEncrypt.ToArray();

                        var result = new byte[iv.Length + decryptedContent.Length];

                        Buffer.BlockCopy(iv, 0, result, 0, iv.Length);
                        Buffer.BlockCopy(decryptedContent, 0, result, iv.Length, decryptedContent.Length);

                        return Convert.ToBase64String(result);
                    }
                }
            }
        }
        public static string DecryptString(string cipherText, string keyString)
        {
            var fullCipher = Convert.FromBase64String(cipherText.Trim());

            var iv = new byte[16];
            var cipher = new byte[16];

            Buffer.BlockCopy(fullCipher, 0, iv, 0, iv.Length);
            Buffer.BlockCopy(fullCipher, iv.Length, cipher, 0, iv.Length);
            var key = Encoding.UTF8.GetBytes(keyString);

            using (var aesAlg = Aes.Create())
            {
                using (var decryptor = aesAlg.CreateDecryptor(key, iv))
                {
                    string result;
                    using (var msDecrypt = new MemoryStream(cipher))
                    {
                        using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                        {
                            using (var srDecrypt = new StreamReader(csDecrypt))
                            {
                                result = srDecrypt.ReadToEnd();
                            }
                        }
                    }

                    return result;
                }
            }
        }

    }
}

After user  login process completed we need to get all user which is connected to the login user as well as all the conversation between them. So we create one more controller and service as below.

IMessageServiceQuery.cs

public interface IMessageServiceQuery
   {
       IEnumerable<Message> GetAll();
       IEnumerable<Message> GetReceivedMessages(string userId);
   }

MessageServiceQuery.cs

using Chat_Application.Entities;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Chat_Application.Interface
{
    public class MessageServiceQuery : IMessageServiceQuery
    {
        protected SimpleChatDbContext Context;
        public MessageServiceQuery(SimpleChatDbContext context)
        {
            Context = context;
        }

        public IEnumerable<Message> GetAll()
        {
            return Context.Message.AsNoTracking().ToList().OrderBy(x => x.MessageDate); ;
        }
        public IEnumerable<Message> GetReceivedMessages(string Id)
        {

            return (IEnumerable<Message>)Context.Message.AsNoTracking().FirstOrDefault(x => x.Id == Id);
        }
    }
}

MessageController.cs

using Chat_Application.Interface;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace Chat_Application.Controllers
{
    [Route("api/message")]
    [ApiController]
    public class MessageController : ControllerBase
    {
        private readonly IMessageServiceQuery messageServiceQuery;
        private readonly IMessageService messageService;
        public MessageController(IMessageServiceQuery _messageServiceQuery, IMessageService _messageService)
        {
            this.messageServiceQuery = _messageServiceQuery;
            this.messageService = _messageService;
        }
        [AllowAnonymous]
        [HttpGet]
        public IActionResult GetAll()
        {
            var messages = this.messageServiceQuery.GetAll();
            return Ok(messages);
        }


        [HttpGet("received-messages/{userId}")]
        public IActionResult GetUserReceivedMessages(string userId)
        {
            var messages = this.messageServiceQuery.GetReceivedMessages(userId);
            return Ok(messages);
        }
    }
}

Now our API is ready for use.

2) Create Angular Project for User Interface

To create new project open the command prompt and navigate to the directory where you want to create project and type the following command.

ng g new chat-app

Now create component for different operation.

ng g c login

ng g c home

ng g c registration

ng g c user

now create AuthGuard which is used to protect the routes from unauthorized access in angular.Create authgurd using following command.

ng g guard authguard

Copy the follwing caode in auth.guard.ts file

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree } from '@angular/router';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {
  constructor(private router: Router) {
  }
  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
      if (localStorage.getItem('token') != null){
        return true;
      }
      else {
        this.router.navigate(['/user/login']);
        return false;
      }
  } 
}

Here, canActivate is like a constructor. It will be called before accessing the routes.

Now create interceptor to  to intercept incoming or outgoing HTTP requests using the HttpClient.

By intercepting the Http request, we can modify or change the value of the request, and by intercepting the response, we can do some predefined actions on a particular status code or message.

auth.interceptor.ts

import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable, tap } from 'rxjs';
import { Router } from "@angular/router";

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor(private router: Router) {
  }


  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    if (localStorage.getItem('token') != null) {
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${localStorage.getItem('token')}`
        }
      });
    }

    return next.handle(request).pipe(
        tap(
            succ => { },
            err => {
                if (err.status == 401){
                    localStorage.removeItem('token');
                    this.router.navigate(['/user/login']);
                }
                else if(err.status == 403)
                this.router.navigateByUrl('/forbidden');
            }
        )
    )
  }
}

Then, create Dto folder and also create dto for messages & use as below:

MessageDto.ts

export class MessageDto {
    public user: string = '';
    public msgText: string = '';
  }

Create interface for User to access userdata.

UserDto.ts

 interface UserDto{
     Id:string;
    FisrtName:string;
    LastName:string;
    UserName:string;
    IsOnline:boolean;
    Email:string;
    Theme:string;
    color:string;
}

First, add routing path in app-routing.module.ts file to redir4ect from one component to another component.

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { ChangePasswordComponent } from './change-password/change-password.component';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { RegistrationComponent } from './registration/registration.component';
import { UserComponent } from './user/user.component';

const routes: Routes = [{path:'',redirectTo:'/user/login',pathMatch:'full'},
{
  path: 'user', component: UserComponent,
  children: [
    
    { path: 'login', component: LoginComponent },
    {path:'registration',component:RegistrationComponent},
    {path:'changepassword',component:ChangePasswordComponent}
  ]
},
{path:'home',component : HomeComponent},
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

app.component.html

<router-outlet></router-outlet>

now copy the code in user.component.html 

<div class="wrapper">
    <div class="wrapped-div">
      <div class="tab-header">
        <h2 routerLink='/user/login' routerLinkActive='active'>Sign In</h2>
        <h2 routerLink='/user/registration' routerLinkActive='active'>Sign Up</h2>
      </div>
      <div class="row">
        <div class="col-md-10 offset-md-1">
          <router-outlet></router-outlet>
        </div>
      </div>
    </div>
  </div>

login.component.html

<div class="container">
<form #form='ngForm' class="mb-4" autocomplete="off" (submit)="onSubmit(form)">
  <div class="form-group">
    <label>UserName</label>
    <input class="form-control"  name="Email" [(ngModel)]="formModel.Email" required>
  </div>
  <div class="form-group">
    <label>Password</label>
    <input class="form-control" type="password" name="Password" [(ngModel)]="formModel.Password" required>
  </div>
  <div class="form-row">
    <div class="form-group col-md-8 offset-md-2">
      <button type="submit" class="btn btn-primary btn-block btn-round" [disabled]="form.invalid">Login</button>
    </div>
  </div>
  <div class="form-row">
    <div class="form-group col-md-8 offset-md-3">
      <a type="submit" href="user/changepassword" *ngIf = "IsForgot" >Forgot Password</a>
    </div>
  </div>
</form>
</div>

login.component.ts

import { Component, OnInit } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Router } from '@angular/router';
import { ChatService } from '../services/chat.service';


@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {

  formModel = {
    Email: '',
    Password: ''
  }
  IsForgot:boolean= false;
  constructor(private service: ChatService, private router: Router) { }

  ngOnInit() {
     if (localStorage.getItem('token') != null)
       this.router.navigateByUrl('/home');
  }

  onSubmit(form: NgForm) {
    this.service.login(form.value).subscribe(
      (res: any) => {
        console.log(res);
        localStorage.setItem('token', res.token);
        localStorage.setItem('login-user', JSON.stringify(res.user));
         this.router.navigateByUrl('/home');
      },
      (      err: { status: number; }) => {
        if (err.status == 400)
        {
          console.log('Incorrect Email.', 'Authentication failed.');
        }
        else if(err.status == 500)
        {
          this.IsForgot = true;
        }
        else
          console.log(err);
      }
    );
  }

}

registration.component.html

<form [formGroup]="service.formModel" autocomplete="off" (submit)="onSubmit()">

    <div class="form-group">
      <label>Email</label>
      <input class="form-control" formControlName="Email">
      <!-- <label class="text-danger" *ngIf="service.formModel.get('Email')?.touched && service.formModel.get('Email')?.errors?">Invalid
        email address.</label> -->
    </div>
    <div class="form-group">
      <label>First Name</label>
      <input class="form-control" formControlName="FirstName">
    </div>
    <div class="form-group">
      <label>Last Name</label>
      <input class="form-control" formControlName="LastName">
    </div>
  <div class="form-group">
    <label>Password</label>
    <input class="form-control" type="password" name="Password" formControlName="Password" required>
  </div> 
    <div class="form-row">
      <div class="form-group col-md-8 offset-md-2">
        <button type="submit" class="btn btn-primary btn-round btn-block" [disabled]="!service.formModel.valid">Sign Up</button>
      </div>
    </div>
  </form>

registration.component.ts

import { Component, OnInit } from '@angular/core';
import { ChatService } from '../services/chat.service';

@Component({
  selector: 'app-registration',
  templateUrl: './registration.component.html',
  styles: []
})
export class RegistrationComponent implements OnInit {

  constructor(public service: ChatService) { }

  ngOnInit() {
    this.service.formModel.reset();
  }

  onSubmit() {
    this.service.register().subscribe(
      (res: any) => {
        if (res.succeeded) {
          this.service.formModel.reset();
        } else {
          res.errors.forEach((element: { code: any; description: any; }) => {
            switch (element.code) {
              case 'DuplicateUserName':
                console.log('Username is already taken','Registration failed.');
                break;

              default:
              console.log(element.description,'Registration failed.');
                break;
            }
          });
        }
      },
      (      err: any)=> {
        console.log(err);
      }
    );
  }

}

home.component.html

<div class="container-fluid">
    <div class="row">
        <div class="col-md-4 col-xl-3 chat">
            <div class="card mb-sm-3 mb-md-0 contacts_card" [ngClass]="isDarkMode === 'Dark' ? 'dark' : ''">
                <div class="card-header">

                    <ul class="contacts">
                        <li class="">
                            <div class="d-flex bd-highlight">
                                <div class="img_cont">
                                    <img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img">
                                    <span class="online_icon"></span>
                                </div>
                                <div class="user_info">
                                    <span>{{loggedInUser.firstName}} {{loggedInUser.lastName}}</span>
                                    <p>{{loggedInUser.email}}</p>
                                </div>
                            </div>
                            <div class="dropdownIcon">
                                <i class="fa fa-ellipsis-h fa-pull-right"  id="dropdownMenuButton" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" ></i>
                                <ul class="dropdown-menu  dropdown-menu-right menuList" aria-labelledby="dropdownMenuButton">
                                    <li><a class="dropdown-item" role="option" href="#">My Profile</a></li>
                                    <li><a class="dropdown-item" role="option" style="cursor: pointer;" (click)="showThemeDialog()">Change Theme</a></li>
                                    <li><a class="dropdown-item" role="option" style="cursor: pointer;" (click)="DeleteAccount()">Delete Account</a></li>
                                    <li><a class="dropdown-item" role="option" style="cursor: pointer;" (click)="onLogout()">Logout</a></li>
                                </ul>
                            </div>
                            
                        </li>
                    </ul>
                    <div class="input-group">
                        <input type="text" placeholder="Search..." name="" class="form-control search" [ngClass]="isDarkMode === 'Dark' ? 'dark' : ''">
                        <div class="input-group-prepend">
                            <span class="input-group-text search_btn"><i class="fas fa-search"></i></span>
                        </div>
                    </div>
                </div>
                <div class="card-body contacts_body">
                    <ul class="contacts">
                        <li style="cursor: pointer;" [class.active]="item.isActive" *ngFor="let item of users" (click)="openChat(item)">
                            <div class="d-flex bd-highlight">
                                <div class="img_cont">
                                    <img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img">
                                    <span class="online_icon" [class.offline]="!item.isOnline"></span>
                                </div>
                                <div class="user_info">
                                    <span>{{item.firstName}} {{item.lastName}}</span>

                                </div>
                            </div>
                        </li>

                    </ul>
                </div>
                <!-- <div class="card-footer"></div> -->
            </div>
        </div>
        <div class="col-md-8 col-xl-9 chat" >
            <div class="card"  [ngClass]="isDarkMode === 'Dark' ? 'dark' : ''">
                <div class="card-header msg_head ">
                    <div class="d-flex bd-highlight">
                       
                        <div class="img_cont">
                            <img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img">
                            <span class="online_icon"></span>
                        </div>
                        <div class="user_info">
                            <span>{{chatUser?.firstName}} {{chatUser?.lastName}}</span>
                        </div>
                        <div class="col"></div>
                        <div class="col-xs-1 icons">                        
                            <img src="../assets/kindpng_404965.png" class="rounded-circle user_img">                          
                        </div>                       
                        <div class="col-xs-1 icons">
                        <button (click)="Call()">
                            <img src="../assets/voice-call.png" class="rounded-circle user_img">
                        </button>
                        </div>

                    </div>
                </div>
                <div class="card-body msg_card_body"  [ngClass]="isDarkMode === 'Dark' ? 'darkbody' : ''">
                    <div *ngFor="let m of displayMessages">
                        <div class="messageItem">
                            <section>
                                <i *ngIf="m.type==='recieved'" class="fa fa-ellipsis-h messageListIcon" style="display: none;" id="{{m.id}}" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></i>
                                <ul class="dropdown-menu userList">
                                    <li><a class="dropdown-item mouseCursor" (click)="deleteMessage(m,'DeleteForMe',false)">Remove Only For Me</a></li>
                                </ul>
                            </section>
                            <div class="d-flex justify-content-start mb-4" *ngIf="m.type==='recieved' && !m.isReceiverDeleted">
                                <div class="img_cont_msg">
                                    <img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img_msg">
                                </div>
                                <div class="msg_cotainer" [ngStyle]="{'background-color':bgColor }" [ngClass]="(isEmoji(m.content) == true) ? 'emojiContent' : 'msg_cotainer'">
                                    {{m.content}}
                                    <span class="msg_time"> {{m.messageDate+ 'Z' | date : 'h:mm a'}} </span>
                                </div>
                            </div>
                        </div>
                        <div class="messageItem">
                            <section>
                                <i *ngIf="m.type==='sent'" class="fa fa-ellipsis-h messageListIcon" aria-hidden="true" style="display: none;" id="{{m.id}}" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false"></i>
                                <ul class="dropdown-menu userList" aria-labelledby="m.id">
                                    <li><a class="dropdown-item mouseCursor" (click)="deleteMessage(m,'DeleteForMe',true)">Remove Only For Me</a></li>
                                    <li><a class="dropdown-item mouseCursor" (click)="deleteMessage(m,'DeleteForEveryone',true)">Remove For Everyone</a></li>
                                </ul>
                            </section>

                            <div class="d-flex justify-content-end mb-4" *ngIf="m.type==='sent' && !m.isSenderDeleted">
                                <div  [ngStyle]="{'background-color':bgColor }"  [ngClass]="(isEmoji(m.content) == true) ? 'emojiContent' : 'msg_cotainer'">
                                    {{m.content}}
                                    <!-- <span *ngIf="isEmoji(m.content)" [ngStyle]="{'font-size':'5em'}"> {{m.content}} </span> -->
                                    <span class="msg_time_send">{{m.messageDate+ 'Z' | date : 'h:mm a'}}</span>
                                </div>
                                <div class="img_cont_msg">
                                    <img src="https://static.turbosquid.com/Preview/001292/481/WV/_D.jpg" class="rounded-circle user_img_msg">
                                </div>
                            </div>
                        </div>

                    </div>
                </div>
                <div class="card-footer">
                    <div class="input-group">
                        <div class="input-group-append">
                            <span class="input-group-text attach_btn"><i class="fas fa-paperclip"></i></span>
                        </div>
                        <textarea name="" [(ngModel)]="message" id="message" class="form-control type_msg" name="message" placeholder="Type your message..." (keyup.enter)="SendDirectMessage()" [ngClass]="isDarkMode === 'Dark' ? 'dark' : ''"></textarea>
                        <div class="input-group-append" (click)="SendDirectMessage()">
                            <span class="input-group-text send_btn"><i class="fas fa-location-arrow"></i></span>
                        </div>
                        <button (click)="isEmojiPickerVisible = !isEmojiPickerVisible;"  class="rounded-circle emoji"><span [innerHTML]="emoji"></span></button>
                        <!-- <emoji-mart class="emoji-mart" *ngIf="isEmojiPickerVisible" (emojiSelect)="addEmoji($event)" title="Choose your emoji"></emoji-mart> -->
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>
<p-dialog [(visible)]="showTheme" [modal]="true" [style]="{width: '30vw'}" [draggable]="false" [resizable]="false"> 
    <ng-template pTemplate="header">
      <h4> Select Theme</h4>
    </ng-template>
    <div class="p-field-radiobutton">
        <p-radioButton name="theme" value="Dark" label="Dark" [(ngModel)]="theme" inputId="theme1"></p-radioButton>&nbsp;
        <p-radioButton name="theme" value="Light" label="Light" [(ngModel)]="theme" inputId="theme2"></p-radioButton>
    </div><br />
    <div>
        <button pButton pRipple type="button" value="pink" class="p-button-rounded" [ngStyle]="{background:'#cf5bd7'}" (click)="setcontentBackgroungcolor('#cf5bd7')" ></button>
        <span icon="pi pi-check" class="p-button-rounded"></span>
        <button pButton  type="button" value="red" class="p-button-rounded" [ngStyle]="{background:'#8277db'}" (click)="setcontentBackgroungcolor('#8277db')" ></button>
        <button pButton pRipple type="button" value="pink" class="p-button-rounded" [ngStyle]="{background:'#67ad6a'}" (click)="setcontentBackgroungcolor('#67ad6a')" ></button>
        <button pButton pRipple type="button" value="pink" class="p-button-rounded"[ngStyle]="{background:'#efa432'}" (click)="setcontentBackgroungcolor('#efa432')" ></button>
        <button pButton pRipple type="button" value="pink" class="p-button-rounded" [ngStyle]="{background:'#a1a4ab'}" (click)="setcontentBackgroungcolor('#a1a4ab')" ></button>
    </div>
    
        <ng-template pTemplate="footer">
            <p-button icon="pi pi-check" (click)="changeTheme()" label="Save" class="p-button-text"></p-button>
        </ng-template>
</p-dialog>             
<p-dialog [(visible)]="isEmojiPickerVisible" [modal]="true" [style]="{width: '25vw'}" [draggable]="false" [resizable]="false"> 
    <emoji-mart class="emoji-mart" *ngIf="isEmojiPickerVisible" (emojiSelect)="addEmoji($event)" title="Choose your emoji"></emoji-mart>
</p-dialog>

home.component.ts

import { Component, OnInit } from '@angular/core';
import { ChatService } from '../services/chat.service';
import {MessageDto } from 'src/app/Dto/MessageDto';
import { Router } from '@angular/router';
import { HubConnection, HubConnectionBuilder } from '@microsoft/signalr';
import { Guid } from 'guid-typescript';
import { DatePipe,Time } from '@angular/common';
import { isNgTemplate } from '@angular/compiler';
import { SharedService } from '../shared.service';
import { PrimeNGConfig } from 'primeng/api';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  Isselected:boolean = false;
  bgColor!:string;
  isDarkMode:string='';
  CurrentTime! : string;
  theme!:string;
  loggedInUser = JSON.parse(localStorage.getItem("login-user")!);
  users:any;
  chatUser:any;
  showTheme:boolean = false;
 isEmojiPickerVisible!: boolean;
 emoji:string='&#128512;';
 lastElement:any;

  messages: any[] = [];
  displayMessages: any[] = []
  message!: string
  hubConnection!: HubConnection;

 
  connectedUsers: any[] = []
  UserConnectionID: any;
  constructor(private router: Router,private chatService : ChatService,public datepipe: DatePipe,private sharedService : SharedService,private primengConfig: PrimeNGConfig) { }

  ngOnInit() {
    this.primengConfig.ripple = true;
    this.sharedService.selectedThemeColorChanged.subscribe(state => {
      this.isDarkMode = state;
    });
    this.theme = this.loggedInUser.theme;
    this.bgColor = this.loggedInUser.color;
    this.lastElement = document.querySelectorAll(".msg_time_send:last-child")
    
     this.chatService.getUserReceivedMessages(this.loggedInUser.id).subscribe((item:any)=>{
       if(item){
         this.messages=item;
         this.messages.forEach(x=>{
          x.type=x.receiver===this.loggedInUser.id?'recieved':'sent';
         })
         console.log(this.messages);
       }
     })
    
    this.chatService.getAll().subscribe(
      (user:any) => {
        console.log("Users"+ user)
        if(user){
        this.users=user.filter((x: { email: any; })=>x.email!==this.loggedInUser.email);
        console.log("User:"+this.users);
        this.users.forEach((item: { [x: string]: boolean; })=>{
          item['isActive']=false;
        })
        this.makeItOnline();
        }
      },
      err => {
        console.log(err);
      },
    );




    this.message = ''
    this.hubConnection = new HubConnectionBuilder().withUrl("https://localhost:44308/chathub").build();
    const self = this
    this.hubConnection.start()
      .then(() => {
        self.hubConnection.invoke("PublishUserOnConnect", this.loggedInUser.id, this.loggedInUser.firstName, this.loggedInUser.userName)
          .then(() => console.log('User Sent Successfully'))
          .catch(err => console.error(err));

        this.hubConnection.on("BroadcastUserOnConnect", Usrs => {
          this.connectedUsers = Usrs;
          this.makeItOnline();
        })
        this.hubConnection.on("BroadcastUserOnDisconnect", Usrs => {
          this.connectedUsers = Usrs;
          this.users.forEach((item: { isOnline: boolean; }) => {
            item.isOnline = false;
          });
          this.makeItOnline();
        })
      })
      .catch(err => console.log(err));

     this.hubConnection.on("UserConnected", (connectionId) => this.UserConnectionID = connectionId);

    this.hubConnection.on('BroadCastDeleteMessage', (connectionId, message) => {
     let deletedMessage=this.messages.find(x=>x.id===message.id);
     if(deletedMessage){
       deletedMessage.isReceiverDeleted=message.isReceiverDeleted;
       deletedMessage.isSenderDeleted=message.isSenderDeleted;
       if(deletedMessage.isReceiverDeleted && deletedMessage.receiver===this.chatUser.id){
        this.displayMessages = this.messages.filter(x => (x.type === 'sent' && x.receiver === this.chatUser.id && x.sender === this.loggedInUser.id) || (x.type === 'recieved' && x.sender === this.chatUser.id && x.receiver === this.loggedInUser.id));
       }
     }

    })

    this.hubConnection.on('ReceiveDM', (connectionId, message) => {
      console.log(message);
      message.type = 'recieved';
      this.messages.push(message);
      let curentUser = this.users.find((x: { id: any; }) => x.id === message.sender);
      this.chatUser = curentUser;
      this.users.forEach((item: { [x: string]: boolean; }) => {
        item['isActive'] = false;
      });
      var user = this.users.find((x: { id: any; }) => x.id == this.chatUser.id);
      user['isActive'] = true;
      this.displayMessages = this.messages.filter(x => (x.type === 'sent' && x.receiver === this.chatUser.id && x.sender === this.loggedInUser.id) || (x.type === 'recieved' && x.sender === this.chatUser.id && x.receiver === this.loggedInUser.id));
    })
  }

  SendDirectMessage() {
    if (this.message != '' && this.message.trim() != '') {
      let guid=Guid.create();
      var msg = {
        id:guid.toString(),
        sender: this.loggedInUser.id,
        receiver: this.chatUser.id,
        messageDate:new Date(),
        type: 'sent',
        content: this.message
      };
     
      //  this.CurrentTime = msg.messageDate.getHours() + ':' + msg.messageDate.getMinutes();

      this.messages.push(msg);
      this.displayMessages = this.messages.filter(x => (x.type === 'sent' && x.receiver === this.chatUser.id && x.sender === this.loggedInUser.id) || (x.type === 'recieved' && x.sender === this.chatUser.id && x.receiver === this.loggedInUser.id));
 
      this.hubConnection.invoke('SendMessageToUser', msg)
        .then(() => console.log('Message to user Sent Successfully'))
        .catch(err => console.error(err));
      this.message = '';
    }
  }

  openChat(user: { [x: string]: boolean; }) {
    this.users.forEach((item: { [x: string]: boolean; }) => {
      item['isActive'] = false;
    });
    user['isActive'] = true;
    this.chatUser = user;
    this.displayMessages = this.messages.filter(x => (x.type === 'sent' && x.receiver === this.chatUser.id && x.sender === this.loggedInUser.id) || (x.type === 'recieved' && x.sender === this.chatUser.id && x.receiver === this.loggedInUser.id));;
  }

  makeItOnline() {
    if (this.connectedUsers && this.users) {
      this.connectedUsers.forEach(item => {
        var u = this.users.find((x: { userName: any; }) => x.userName == item.username);
        if (u) {
          u.isOnline = true;
        }
      })
    }
  }
  deleteMessage(message: { isSenderDeleted: any; isReceiverDeleted: boolean; },deleteType: any,isSender: any){
    let deleteMessage={
      'deleteType':deleteType,
      'message':message,
      'deletedUserId':this.loggedInUser.id
    }
    this.hubConnection.invoke('DeleteMessage', deleteMessage)
        .then(() => console.log('publish delete request'))
        .catch(err => console.error(err));
    message.isSenderDeleted=isSender;
    message.isReceiverDeleted=!isSender;
  }

  onLogout() {
    this.hubConnection.invoke("RemoveOnlineUser", this.loggedInUser.id)
      .then(() => {
        this.messages.push('User Disconnected Successfully')
      })
      .catch(err => console.error(err));
    localStorage.removeItem('token');
    this.router.navigate(['/user/login']);
  }
  showThemeDialog(){
    this.showTheme = true;
  }
  changeTheme(){
    console.log(this.theme);
    if(this.theme == 'Dark'){
      this.loggedInUser.theme = 'Dark';
        this.sharedService.updateSelectedThemeChanged(this.theme);
    }
    else{
      this.loggedInUser.theme = 'Light';
      this.sharedService.updateSelectedThemeChanged(this.theme);
      
    }
    this.loggedInUser.color = this.bgColor;
    localStorage.setItem('login-user', JSON.stringify(this.loggedInUser));
    this.updateUser(this.loggedInUser);
    this.showTheme = false;
  }
  setcontentBackgroungcolor(color:any){
    this.bgColor = color;
    this.Isselected = true;
  }
  updateUser(user:any){
    this.chatService.updateUser(user).subscribe(res =>{
      console.log("User Updated Successfully.....");
    });
  }
 addEmoji(event:any) {
    this.message = `${this.message}${event.emoji.native}`;
    this.isEmojiPickerVisible = false;
 }
 
isEmoji(str:any) {
  var emoji_regex = /^(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])+$/;

 const isem = emoji_regex.test(str);
 return isem;

}
DeleteAccount(){

 
}
Call(){
 
  this.sharedService.currentChatUser(this.chatUser);
  this.router.navigate(['/voice-call']);
}
}

home.component.css

.bg-gray {
    background-color: #ececec;
}

.chat {
    margin-top: auto;
    margin-bottom: auto;
    padding:0;
}

.card {
    height: 60em;
}
.icons{
    padding:0 5px;
}
.contacts_body {
    padding: 0.75rem 0 !important;
    overflow-y: auto;
    white-space: nowrap;
}

.msg_card_body {
    overflow-y: auto;
}

.card-header {
    border-radius: 15px 15px 0 0 !important;
    border-bottom: 0 !important;
}

.card-footer {
    border-radius: 0 0 15px 15px !important;
    border-top: 0 !important;
}

.container {
    align-content: center;
}

.search {
    border-radius: 15px 0 0 15px !important;

}

.search:focus {
    box-shadow: none !important;
    outline: 0px !important;
}

.type_msg {
    height: 60px !important;
    overflow-y: auto;
}

.type_msg:focus {
    box-shadow: none !important;
    outline: 0px !important;
}

.attach_btn {
    border-radius: 15px 0 0 15px !important;
    background-color: rgba(0, 0, 0, 0.3) !important;
    border: 0 !important;
    color: white !important;
    cursor: pointer;
}

.send_btn {
    border-radius: 0 15px 15px 0 !important;
    background-color: rgba(0, 0, 0, 0.3) !important;
    border: 0 !important;
    color: white !important;
    cursor: pointer;
}

.search_btn {
    border-radius: 0 15px 15px 0 !important;
    background-color: rgba(0, 0, 0, 0.3) !important;
    border: 0 !important;
    color: white !important;
    cursor: pointer;
}

.contacts {
    list-style: none;
    padding: 0;
}

.contacts li {
    width: 100% !important;
    padding: 5px 10px;
    margin-bottom: 15px !important;
}

.contacts li:hover {
    background-clip: #eee;
}

.active {
    background-color: #daeff7;
}

.user_img {
    height: 48px;
    width: 48px;
    border: 1.5px solid #f9f9f9;

}

.user_img_msg {
    height: 40px;
    width: 40px;
    border: 1.5px solid #f9f9f9;

}

.img_cont {
    position: relative;
    height: 46px;
    width: 46px;
}

.img_cont_msg {
    height: 40px;
    width: 40px;
}

.online_icon {
    position: absolute;
    height: 15px;
    width: 15px;
    background-color: #4cd137;
    border-radius: 50%;
    bottom: 0.2em;
    right: 0.4em;
    border: 1.5px solid white;
}

.offline {
    background-color: #c23616 !important;
}

.user_info {
    margin-top: auto;
    margin-bottom: auto;
    margin-left: 15px;
}

.user_info span {
    font-size: 18px;
}

.user_info p {
    font-size: 12px;
}

.video_cam {
    margin-left: 50px;
    margin-top: 5px;
}

.video_cam span {
    color: #0d6efd;
    font-size: 20px;
    cursor: pointer;
    margin-right: 20px;
}

.msg_cotainer {
    margin-top: auto;
    margin-bottom: auto;
    margin-left: 10px;
    border-radius: 10px;
    background-color: rgba(0, 0, 0, 0.3);
    color:white;
    padding: 10px;
    position: relative;
}

.msg_cotainer_send {
    margin-top: auto;
    margin-bottom: auto;
    margin-right: 10px;
    border-radius: 10px;
    background-color:rgba(0, 0, 0, 0.3);
    color:white;
    padding: 10px;
    position: relative;
}

.msg_time {
    position: absolute;
    left: 15px;
    top: -22px;
    font-size: 12px;
    min-width: 160px;
    color: #999;
}

.msg_time_send {
    position: absolute;
    right: 15px;
    top: -22px;
    font-size: 12px;
    color: #999;
    min-width: 160px;
    text-align: right;
}

.msg_head {
    position: relative;
    /* background-color: #f0f4f8; */
}

#action_menu_btn {
    position: absolute;
    right: 10px;
    top: 10px;
    color: white;
    cursor: pointer;
    font-size: 20px;
}

.action_menu {
    z-index: 1;
    position: absolute;
    padding: 15px 0;
    background-color: rgba(0, 0, 0, 0.5);
    color: white;
    border-radius: 15px;
    top: 30px;
    right: 15px;
    display: none;
}

.action_menu ul {
    list-style: none;
    padding: 0;
    margin: 0;
}

.action_menu ul li {
    width: 100%;
    padding: 10px 15px;
    margin-bottom: 5px;
}

.action_menu ul li i {
    padding-right: 10px;

}

.action_menu ul li:hover {
    cursor: pointer;
    background-color: rgba(0, 0, 0, 0.2);
}

.contacts_card {
    /* background-color: #f0f4f8; */
    color: #333;
}

@media(max-width: 576px) {
    .contacts_card {
        margin-bottom: 15px !important;
    }
}

.dropdownIcon {
    position: absolute;
    right: 20px;
    top: 25px;

}

.dropdownIcon i {
    font-size: 20px;
    cursor: pointer;
}

.menuList {
    margin: 0;
    padding: 0;
    list-style: none;
    background-color: #ececec;
    border-radius: 6px;
    position: relative;
    z-index: 999;
    top: 22px;
    max-width: 200px;
    right: 0;
}

.menuList li,
.userList li {
    margin-bottom: 0 !important;
}

.dropdown-item:focus,
.dropdown-item:hover {
    background-color: #daeff7;
}

.positionRelative {
    position: relative;
}

.messageItem {
    position: relative;
    cursor: pointer;
    padding-right: 30px;
}

.messageListIcon {
    position: absolute;
    right: 0;
    top: 0;
}

.messageItem:hover .messageListIcon {
    display: block !important;
}

.userList {
    margin: 0;
    padding: 0;
    list-style: none;
    background-color: #ececec;
    position: absolute;
    right: 10px;
    z-index: 999;
    top: 15px;
    max-width: 200px;
}
.mouseCursor{
    cursor: pointer;
}
.dark{
    background-color: rgba(0,0,0,0.9);
    color:gray;
 
}
.darkbody{
    background-color: rgba(0,0,0);
    color:gray;
}
:host ::ng-deep button {
    margin-right: .5em;
}
.emojiContent{
    font-size:5em;
    background-color: transparent !important;
}
.emoji{
    position:relative;
    top: 8px;
    right: 100px;
    font-size:20px;
    height:45px;
    width:45px;
    border-radius: 10px;
}

Now, create shared service  and chat service by using this command.

ng g s shared

ng g s chat

shared.service.ts

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

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

  constructor() { }
  loggedInUser = JSON.parse(localStorage.getItem("login-user")!);

  public chatUser = new BehaviorSubject<string>('');
  selectedchatUser = this.chatUser.asObservable();

  public selectedThemeColor = new BehaviorSubject<string>(this.loggedInUser.theme);
  selectedThemeColorChanged = this.selectedThemeColor.asObservable();

  updateSelectedThemeChanged(state: string): void {
    this.selectedThemeColor.next(state);
}
currentChatUser(state:string):void{
  this.chatUser.next(state);
}
}

chat.service.ts

import { Injectable, OnInit } from '@angular/core';
import * as signalR from '@microsoft/signalr';          // import signalR
import { HttpClient } from '@angular/common/http';
import { MessageDto } from '../Dto/MessageDto';
import { Observable, Subject } from 'rxjs';
import { FormBuilder, Validators } from '@angular/forms';
import { environment as env } from '../../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class ChatService {
  private receivedMessageObject: MessageDto = new MessageDto();
  private sharedObj = new Subject<MessageDto>();

  constructor(private http: HttpClient,private fb: FormBuilder) {}

  UserID:any
  UserFullName : any
  UserN : any
  formModel = this.fb.group({
    Email: ['', Validators.email],
    FirstName: [''],
    LastName: [''],
    Password:['']
  });
  register() {
    var body = {
      UserName: this.formModel.value.Email,
      Email: this.formModel.value.Email,
      FirstName: this.formModel.value.FirstName,
      LastName: this.formModel.value.LastName,
      Password:this.formModel.value.Password
    };
    return this.http.post(env.apiUrl +'/account/Register', body);
  }

  login(formData: any) {
    return this.http.post(env.apiUrl +'/account/Login', formData)
  }

  
  getAll() {
    return this.http.get( env.apiUrl +'/account');
  }


  private mapReceivedMessage(user: string, message: string): void {
    this.receivedMessageObject.user = user;
    this.receivedMessageObject.msgText = message;
    this.sharedObj.next(this.receivedMessageObject);
 }

  /* ****************************** Public Mehods **************************************** */



  public retrieveMappedObject(): Observable<MessageDto> {
    return this.sharedObj.asObservable();
  }

  getUserReceivedMessages(userId:string) {
    return this.http.get(env.apiUrl +'/message');
  }
  deleteMessage(message:any) {
    return this.http.post(env.apiUrl +'/message',message);
  }
  updateUser(user:any){
    return this.http.patch(env.apiUrl +'/account/updateUser',user);
  }
  call(user:any){
    return this.http.post(env.apiUrl+'/Token/Connect',user);
  }

add API url to environment.ts file

And run the project in visual studio and wirte npm start command in visual studio code.

Conclusion:

By using signalr we connect two user using id and provide connection between them.

OUTPUT:

1 Comment

  1. Filippo Albertini

    Hi Monika, is it possible to download the code ? Thanks

    0
    0
    Reply

Submit a Comment

Your email address will not be published. Required fields are marked *

Subscribe

Select Categories