Closed rcampion closed 2 years ago
Same problem
I came up with a workaround.
HTML(add #ngChatInstance) <ng-chat #ngChatInstance [adapter]="adapter" [userId]="userId" [title]="title" [isCollapsed]="isCollapsed" [browserNotificationsEnabled]="browserNotificationsEnabled">
In the component that instantiates the chat adapter ... @ViewChild('ngChatInstance', { static: true }) protected ngChatInstance: IChatController;
import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { IChatController } from 'ng-chat';
Construct the ChatAdapter with the DataSharingService.
Set the value of ngChatInstance in the DataSharingService.
this.dataSharingService.ngChatInstance.next(this.ngChatInstance);
In the ChatAdapter ... before the call to onMessageReceived, call triggerOpenChatWindow(user);
this.ngChatInstance = this.dataSharingService.ngChatInstance.value;
this.ngChatInstance.triggerOpenChatWindow(user);
this.onMessageReceived(user, post);
Same problem
@rcampion
this.ngChatInstance = this.dataSharingService.ngChatInstance.value;
If possible send the code because your explanation was difficult to understand.
`import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { IChatController } from 'ng-chat';
@Injectable({
providedIn: 'root'
})
export class DataSharingService {
public ngChatInstance: BehaviorSubject
<ng-chat #ngChatInstance [adapter]="adapter" [userId]="userId" [title]="title" [isCollapsed]="isCollapsed" [browserNotificationsEnabled]="browserNotificationsEnabled" [emojisEnabled]="emojisEnabled" [fileUploadUrl]=fileUploadUrl> </ng-chat>
`import { ChatAdapter, IChatGroupAdapter, Group, Message, ChatParticipantStatus, ParticipantResponse, ChatParticipantType, IChatParticipant, MessageType, IChatController, User } from 'ng-chat'; import { Observable, of, BehaviorSubject, Subject } from 'rxjs'; import { delay, finalize, takeUntil } from "rxjs/operators"; import { ChatService } from './chat.service'; import { Injectable } from '@angular/core'; import { AppService } from './app.service'; import { Cookie } from 'ng2-cookies'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { map, catchError } from 'rxjs/operators'; import { ErrorHandlerService } from './error-handler.service'; import { UserContact } from '../interface/user-contact.model'; import { ContactsService } from './contacts.service'; import { ChatParticipant } from '../models/chatParticipant'; import { PaginationPropertySort } from '../interface/pagination'; import { environment } from 'src/environments/environment'; import { UsersService } from './users.service'; import { DataSharingService } from './datasharing.service'; import { SocketClientSixService } from './socket-client-six.service'; import { SocketClientSevenService } from './socket-client-seven.service';
import { ActiveFriendsService } from './active-friends.service';
@Injectable({ providedIn: 'root' }) export class OpenfireAdapter extends ChatAdapter implements IChatGroupAdapter {
public ngChatInstance: IChatController;
public participants: Array<ChatParticipant> = [];
public mockedHistory: Array<Message> = [];
private contactsSubject = new BehaviorSubject<UserContact[]>([]);
private loadingSubject = new BehaviorSubject<boolean>(false);
public loading$ = this.loadingSubject.asObservable();
public total = 0;
public title = "Messaging";
public userId: number;
public filter: string;
public sortProperty: string;
public sortDirection: string;
public pageIndex: number;
public pageSize: number;
messages91: any;
mysubid91 = 'my-subscription-id-091';
messages92: any;
mysubid92 = 'my-subscription-id-092';
messages33: any;
mysubid33 = 'my-subscription-id-033';
private unsubscribeSubject: Subject<void> = new Subject<void>();
xmpp: any;
isUserLoggedIn = false;
isDataReady = false;
firstLoad = true;
constructor(private http: HttpClient,
private wsDataServiceSix: SocketClientSixService,
private wsDataServiceSeven: SocketClientSevenService,
private chatService: ChatService,
private userService: UsersService,
private appService: AppService,
private contactsService: ContactsService,
private dataSharingService: DataSharingService,
private errorService: ErrorHandlerService,
private activeFriendsService: ActiveFriendsService) {
super();
this.wsDataServiceSix.connect().subscribe(res => {
console.log(res);
this.messages91 = this.activeFriendsService
.onUpdate(this.mysubid91)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(post => {
const isLoggedIn = this.appService.checkCredentials();
if ((post.message === 'Session Expired')
|| (post.message === 'Logged In')
|| (post.message === 'Logged Out')
|| (post.message == 'User Contacts Changed')) {
if (isLoggedIn) {
this.userId = this.userService.getUserId();
this.refreshFriends();
}
}
});
});
this.wsDataServiceSeven.connect().subscribe(res => {
console.log(res);
this.messages92 = this.chatService
.onUpdate(this.mysubid92)
.pipe(takeUntil(this.unsubscribeSubject))
.subscribe(post => {
console.log(post);
const user = this.participants.find(x => x.id === post.fromId);
const systemUser = this.userService.getCurrentUser();
if ((post.fromId !== systemUser.contactId)
&& (post.toId === systemUser.contactId)) {
this.ngChatInstance = this.dataSharingService.ngChatInstance.value;
this.ngChatInstance.triggerOpenChatWindow(user);
this.onMessageReceived(user, post);
}
this.mockedHistory.push(post);
});
});
/*
this.xmpp = client({
service: "wss://www.zdslogic.com:7443/ws/",
domain: "zdslogic",
resource: "anonymous",
username: "richard.campion",
password: "ArcyAdmin8246+",
});
this.xmpp.start().catch(console.error);
*/
this.dataSharingService.isUserLoggedIn.subscribe(value => {
this.isUserLoggedIn = value;
if (this.isUserLoggedIn) {
const isLoggedIn = this.appService.checkCredentials();
if (isLoggedIn) {
this.userId = this.userService.getUserId();
} else {
this.dataSharingService.isActiveContactsReady.subscribe(value => {
this.isDataReady = value;
if (this.isDataReady && this.isUserLoggedIn && this.firstLoad) {
this.userId = this.userService.getUserId();
this.firstLoad = false;
}
});
}
}
});
}
listFriends(): Observable<ParticipantResponse[]> {
this.dataSharingService.isUserLoggedIn.subscribe(value => {
this.isUserLoggedIn = value;
});
const isLoggedIn = this.appService.checkCredentials();
if (isLoggedIn) {
this.userId = this.userService.getUserId();
} else {
this.dataSharingService.isActiveContactsReady.subscribe(value => {
this.isDataReady = value;
if (this.isDataReady && this.isUserLoggedIn && this.firstLoad) {
this.userId = this.userService.getUserId();
this.firstLoad = false;
}
});
}
this.loadingSubject.next(true);
if (isLoggedIn) {
this.findAllUserFriends(this.userId).subscribe(response => {
this.participants = [];
response.forEach(element => {
this.participants.push(element.participant);
});
const responses: ParticipantResponse[] = this.participants.map(user => {
const participantResponse = new ParticipantResponse();
//user.status = ChatParticipantStatus.Online;
//user.avatar = null;
//user.participantType = ChatParticipantType.User;
participantResponse.participant = user;
return participantResponse;
});
this.friendsListChangedHandler(responses);
});
return this.findAllUserFriends(this.userId);
}
return of([]);
}
public refreshFriends() {
const isLoggedIn = this.appService.checkCredentials();
if (isLoggedIn) {
this.findAllUserFriends(this.userId).subscribe(response => {
this.participants = [];
response.forEach(element => {
this.participants.push(element.participant);
});
const responses: ParticipantResponse[] = this.participants.map(user => {
const participantResponse = new ParticipantResponse();
//user.status = ChatParticipantStatus.Online;
//user.avatar = null;
//user.participantType = ChatParticipantType.User;
participantResponse.participant = user;
return participantResponse;
});
this.friendsListChangedHandler(responses);
});
}
}
getMessageHistory(destinataryId: any): Observable<Message[]> {
let mockedHistory: Array<Message> = [];
/*
mockedHistory = [
{
fromId: MessageType.Text,
toId: 999,
message: "Hi there, here is a sample image type message:",
dateSent: new Date()
},
{
fromId: 1,
toId: 999,
type: MessageType.Image,
message: "https://66.media.tumblr.com/avatar_9dd9bb497b75_128.pnj",
dateSent: new Date()
},
{
fromId: MessageType.Text,
toId: 999,
message: "Type any message bellow to test this Angular module.",
dateSent: new Date()
},
];
*/
return of(mockedHistory).pipe(delay(2000));
}
sendMessage(message: Message): void {
setTimeout(() => {
let replyMessage = new Message();
replyMessage.message = "You have typed '" + message.message + "'";
replyMessage.dateSent = new Date();
if (isNaN(message.toId)) {
let group = this.participants.find(x => x.id == message.toId) as Group;
// Message to a group. Pick up any participant for this
let randomParticipantIndex = Math.floor(Math.random() * group.chattingTo.length);
replyMessage.fromId = group.chattingTo[randomParticipantIndex].id;
let messageToId = message.toId.toString();
replyMessage.toId = messageToId;
this.onMessageReceived(group, replyMessage);
}
else {
let messageToId = message.toId.toString();
replyMessage.toId = messageToId;
//replyMessage.fromId = message.toId;
let messageFromId = message.fromId.toString();
replyMessage.toId = messageFromId;
let user = this.participants.find(x => x.id == message.fromId);
//this.onMessageReceived(user, replyMessage);
/*
this.xmpp.on("online", async (address) => {
// Makes itself available
await this.xmpp.send(xml("presence"));
// Sends a chat message to itself
const message = xml(
"message",
{ type: "chat", to: address },
xml("body", {}, replyMessage),
);
await this.xmpp.send(message);
});
*/
}
const systemUser = this.userService.getCurrentUser();
message.fromId = systemUser.contactId;
this.chatService.save({ ...message, id: '1' });
}, 1000);
}
groupCreated(group: Group): void {
this.participants.push(group);
this.participants = this.participants.sort((first, second) =>
second.displayName > first.displayName ? -1 : 1
);
// Trigger update of friends list
this.listFriends().subscribe(response => {
this.onFriendsListChanged(response);
});
}
refresh(userId: number) {
this.userId = userId;
this.loadUserContacts(
this.userId,
this.filter,
this.sortProperty,
this.sortDirection,
this.pageIndex,
this.pageSize,
)
}
loadUserContacts(
userId: number,
filter: string,
sortProperty: string,
sortDirection: string,
pageIndex: number,
pageSize: number) {
this.loadingSubject.next(true);
const sort = new PaginationPropertySort();
sort.property = sortProperty;
sort.direction = sortDirection;
this.userId = userId;
this.filter = filter;
this.sortProperty = sortProperty;
this.sortDirection = sortDirection;
this.pageIndex = pageIndex;
this.pageSize = pageSize;
this.contactsService.findUserContactsWithSortAndFilter(userId, filter, sort,
pageIndex, pageSize).pipe(
catchError(() => of([])),
finalize(() => this.loadingSubject.next(false))
)
.subscribe(response => {
this.contactsSubject.next(response.content);
this.total = response.totalElements;
}
);
}
findUserFriendsWithSortAndFilter(
userId = 0,
filter = '', sort: PaginationPropertySort,
pageNumber = 0, pageSize = 3): Observable<any> {
const id: number = userId;
const buildApiUrl = 'user/contacts/friends/' + id;
let apiUrl = this.createCompleteRoute(buildApiUrl, environment.api_url);
const paramsx: any = { page: pageNumber, size: pageSize };
if (sort != null) {
paramsx.sort = sort.property + ',' + sort.direction;
}
let sortTest = sort.direction;
if (sort.property !== '') {
sortTest = sort.property + ',' + sort.direction;
}
let search: string;
if (filter !== '') {
apiUrl = this.createCompleteRoute('contact/search', environment.api_url);
search = 'firstName==*' + filter + '* or ' + 'lastName==*' + filter + '* or ' + 'company==*' + filter + '*';
}
return this.http.get(apiUrl, {
headers: new HttpHeaders(
{
'Content-type': 'application/x-www-form-urlencoded; charset=utf-8',
'Authorization': 'Bearer ' + Cookie.get('access_token')
}),
params: new HttpParams()
.set('search', search)
.set('sort', sortTest)
.set('page', pageNumber.toString())
.set('size', pageSize.toString())
})
.pipe(
//map(res => res['content']),
map(res => res),
catchError(error => { this.errorService.handleError(error); return Observable.throw(error.statusText); })
);
}
findAllUserFriends(userId = 0,): Observable<any> {
const id: number = userId;
const buildApiUrl = 'user/contacts/friends/' + id;
let apiUrl = this.createCompleteRoute(buildApiUrl, environment.api_url);
return this.http.get(apiUrl, {
headers: new HttpHeaders(
{
'Content-type': 'application/x-www-form-urlencoded; charset=utf-8',
'Authorization': 'Bearer ' + Cookie.get('access_token')
}),
})
.pipe(
//map(res => res['content']),
map(response => response),
catchError(error => { this.errorService.handleError(error); return Observable.throw(error.statusText); })
);
}
private createCompleteRoute = (route: string, envAddress: string) => {
return `${envAddress}/${route}`;
}
private generateHeaders() {
return {
headers: new HttpHeaders(
{
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Authorization': 'Bearer ' + Cookie.get('access_token')
})
};
}
private generateHeadersNoToken() {
return {
headers: new HttpHeaders(
{
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*'
})
};
}
}`
`import { Component, OnInit, Output, EventEmitter, AfterViewInit, OnDestroy, ViewChild, AfterContentInit, ChangeDetectorRef } from '@angular/core'; import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http'; import { Router, NavigationEnd } from '@angular/router'; import { User } from '../../core/models/user'; import { ChatAdapter, IChatController } from 'ng-chat'; import { Cookie } from 'ng2-cookies';
import { AppService } from 'src/app/core/services/app.service';
import { SocketClientSixService } from 'src/app/core/services/socket-client-six.service'; import { SocketClientSevenService } from 'src/app/core/services/socket-client-seven.service';
import { ChatService } from 'src/app/core/services/chat.service'; import { UsersService } from 'src/app/core/services/users.service'; import { ContactsService } from 'src/app/core/services/contacts.service'; import { DataSharingService } from 'src/app/core/services/datasharing.service'; import { ErrorHandlerService } from 'src/app/core/services/error-handler.service'; import { OpenfireAdapter } from 'src/app/core/services/openfire-adapter'; import { ActiveFriendsService } from 'src/app/core/services/active-friends.service'; import { NgChatFriendsListComponent } from 'ng-chat/ng-chat/components/ng-chat-friends-list/ng-chat-friends-list.component'; import { NgChat } from 'ng-chat/ng-chat/ng-chat.component'; import { MyAdapter } from 'src/app/core/services/my-adapter'; import { environment } from 'src/environments/environment';
@Component({ selector: 'app-header', providers: [AppService], templateUrl: './header.component.html', styleUrls: ['./header.component.scss'] }) export class HeaderComponent implements OnInit, AfterViewInit, AfterContentInit, OnDestroy {
@Output() public sidenavToggle = new EventEmitter();
currentUser: User;
@ViewChild('ngChatInstance', { static: true }) protected ngChatInstance: IChatController;
userId = 999;
title = 'Messaging';
isCollapsed = true;
browserNotificationsEnabled = false;
theme = 'dark';
emojisEnabled = true;
fileUploadUrl = '';
mySubscription: any;
isUserLoggedIn: boolean = false;
public adapter: OpenfireAdapter = null;
constructor(
private ref: ChangeDetectorRef,
private router: Router,
private http: HttpClient,
private wsDataServiceSix: SocketClientSixService,
private wsDataServiceSeven: SocketClientSevenService,
private chatService: ChatService,
public userService: UsersService,
private appService: AppService,
private contactsService: ContactsService,
private dataSharingService: DataSharingService,
private errorService: ErrorHandlerService,
private activeFriendsService: ActiveFriendsService) {
this.fileUploadUrl = this.createCompleteRoute('uploadChatFile', environment.api_url);
this.adapter = new OpenfireAdapter(this.http,
this.wsDataServiceSix,
this.wsDataServiceSeven,
this.chatService,
this.userService,
this.appService,
this.contactsService,
this.dataSharingService,
this.errorService,
this.activeFriendsService);
this.router.routeReuseStrategy.shouldReuseRoute = function () {
return false;
};
this.mySubscription = this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
// Trick the Router into believing it's last link wasn't previously loaded
this.router.navigated = false;
}
});
}
ngOnInit() {
const isLoggedIn = this.appService.checkCredentials();
const i = window.location.href.indexOf('code');
if (!isLoggedIn && i !== -1) {
this.appService.retrieveToken(window.location.href.substring(i + 5));
}
this.userService.currentUser.subscribe(
(userData) => {
this.currentUser = userData;
this.userId = +this.currentUser.contactId;
}
);
}
ngAfterViewInit(): void {
// Subscribe here, this will automatically update
// "isUserLoggedIn" whenever a change to the subject is made.
this.dataSharingService.isUserLoggedIn.subscribe(value => {
this.isUserLoggedIn = value;
if (this.isUserLoggedIn) {
this.adapter.refreshFriends();
this.dataSharingService.ngChatInstance.next(this.ngChatInstance);
}
});
}
ngAfterContentInit(): void {
this.ref.detectChanges();
}
ngOnDestroy(): void {
if (this.mySubscription) {
this.mySubscription.unsubscribe();
}
}
public onToggleSidenav = () => {
this.sidenavToggle.emit();
}
login() {
this.userService.purgeAuth();
this.appService.login();
}
logout(): void {
this.userService.logout();
this.appService.logout();
}
public redirectToRegister = () => {
const url = `/register`;
this.router.navigate([url]);
}
private createCompleteRoute = (route: string, envAddress: string) => {
return `${envAddress}/${route}`;
}
private generateHeaders() {
return {
headers: new HttpHeaders(
{
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Authorization': 'Bearer ' + Cookie.get('access_token')
})
};
}
} `
I posted the code on this github issue.
Basically, in my code, it is the HeaderComponent that instantiates the chat adapter.
In the header.component.html see the #ngChatInstance reference for the ViewChild:
<ng-chat #ngChatInstance ...
See the @ViewChild in HeaderComponent typescript.
I have a data sharing service See DataSharingService. It gets injected when the HeaderComponent is constructed.
In the constructor of HeaderComponent, instantiate YOUR adapter with the data sharing service.
In the HeaderComponent, ngAfterViewInit(), I set the chat instance that has just been constructed into the data sharing service.
Not sure what you are doing for a server. I am using Java/Springboot with WebSocket for browser communication.
I have a ChatService that is subscribed to in the chat adapter.
In the end all I am doing is calling triggerOpenChatWindow before the onMessageReceived.
Good luck.
On Wed, May 5, 2021 at 10:37 PM Juliano Carvalho @.***> wrote:
this.ngChatInstance = this.dataSharingService.ngChatInstance.value;
If possible send the code because your explanation was difficult to understand.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/rpaschoal/ng-chat/issues/180#issuecomment-833181938, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABBF7HVIMT4USZK42A4VNN3TMH6IBANCNFSM4WDARWWQ .
-- Richard Campion @.*** http://www.richardcampion.com http://www.linkedin.com/in/richardcampion
First message Opens window but message is not displayed.
Testing with Chrome and Firefox.