It seems like I might be overlooking something. Currently, my subscription is set up in a way that local changes made with the typeWriter function inside the component do not update the UI accordingly. The UI only updates when changeDetectorRef.detectChanges() is used, which doesn't seem to be the most efficient method for handling local changes.
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IconDefinition, faCopy } from '@fortawesome/free-solid-svg-icons';
import { HotToastService } from '@ngneat/hot-toast';
import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs';
import { InitialState } from '../../../../../../store/store';
import { storeActions } from '../../../../../../store/store.actions';
import { selectPrinting } from '../../../../../../store/store.selectors';
import { MessageI } from './message.types';
@Component({
selector: 'app-message',
templateUrl: './message.component.html',
styleUrl: './message.component.scss',
})
export class MessageComponent implements OnInit, OnDestroy {
/**
* Chat object which contains properties {from & message}
*/
@Input() chat: MessageI;
private subscriptions: Subscription[] = [];
public printing$: boolean;
public copyIcon: IconDefinition = faCopy;
public copyIconStyle = {
dimensions: {
height: 20,
width: 20,
},
style: { color: 'white', cursor: 'pointer', width: 'max-content' },
};
public setIntervalID: number;
public printedMessage: string = '';
get imageUrl(): string {
return this.chat.from === 'You'
? 'assets/images/me.jpg'
: 'assets/images/cat.png';
}
constructor(
private toast: HotToastService,
private store: Store<{ store: InitialState }>
) {}
ngOnInit(): void {
this.subscriptions.push(
this.store.select(selectPrinting).subscribe((vl) => {
this.printing$ = vl;
})
);
if (this.chat.from === 'You') {
this.printedMessage = this.chat.message;
return;
}
this.typewriterEffect(50);
this.store.dispatch(storeActions.printingHandler());
}
ngOnDestroy(): void {
this.subscriptions.forEach((s) => s.unsubscribe());
}
copyMessage() {
this.toast.success('Copied to clipboard!', {
duration: 5000,
style: {
border: '1px solid #713200',
padding: '16px',
color: '#713200',
},
iconTheme: {
primary: '#713200',
secondary: '#FFFAEE',
},
});
navigator.clipboard.writeText(this.chat.message);
}
typewriterEffect(speed: number) {
// Has to be used from window otherwise theres typescript errors that it needs to be Nodejs.Timeout which prompts another error
// conflicts with Nodejs enviroments
this.setIntervalID = window.setInterval(() => {
if (
this.printedMessage.length !== this.chat.message.length &&
this.printing$
) {
this.printedMessage = this.chat.message.slice(
0,
this.printedMessage.length + 1
);
} else {
this.store.dispatch(storeActions.printingHandler());
clearInterval(this.setIntervalID);
}
}, speed);
}
}