I am trying to build an idle rpg game using Angular. I have a console log displaying events like Damage Dealt / Experience earned.
I have a service call MessageService where I have an array property of type Message (text, date, type).
import { Message } from "@core/models/message";
import { Injectable } from "@angular/core";
import { MESSAGE } from "@core/constant/constant";
@Injectable({
providedIn: "root"
})
export class MessageService {
messages: Message[] = [];
private add(message: String, type: string) {
this.messages.push(new Message(message, type));
}
addGeneralMessage(message: String) {
this.add(message, MESSAGE.GENERAL);
}
addCombatMessage(message: String) {
this.add(message, MESSAGE.COMBAT);
}
clear() {
this.messages = [];
}
constructor() {}
}
I have buttons over my console log allowing user to "filter" all the message to only get specific type (Combat / General / System).
I can filter using : messages.filter(message => message.type == type), what i can't do is keep getting new message of the type selected.
import { Message } from "@core/models";
import { MESSAGE } from "@core/constant/constant";
import { MessageService } from "@core/services";
import { Component, OnInit } from "@angular/core";
@Component({
selector: "app-message",
templateUrl: "./message.component.html",
styleUrls: ["./message.component.scss"]
})
export class MessageComponent implements OnInit {
messages: Message[];
constructor(public messageService: MessageService) {}
ngOnInit() {
this.messages = this.messageService.messages;
}
filterByType(type: String) {
if (type == MESSAGE.ALL) {
this.messages = this.messageService.messages;
} else {
this.messages = this.messageService.messages.filter(
item => item.type == type
);
}
}
}
Any idea ? I tried using observable without success, I think I might not have implement it well.
EDIT : My message component look like that :
<div class="log">
<app-message-button-menu
(filter)="filterByType($event)"
></app-message-button-menu>
<app-message-chat [messages]="messages"></app-message-chat>
</div>
my app-message-button-menu like that :
<div class="menuLog">
<app-message-button
[text]="'All'"
[type]="MESSAGE.ALL"
[active]="activeButton == MESSAGE.ALL"
(messageType)="onFilter($event)"
></app-message-button>
<app-message-button
[text]="'General'"
[type]="MESSAGE.GENERAL"
[active]="activeButton == MESSAGE.GENERAL"
(messageType)="onFilter($event)"
></app-message-button>
<app-message-button
[text]="'Fight'"
[type]="MESSAGE.COMBAT"
[active]="activeButton == MESSAGE.COMBAT"
(messageType)="onFilter($event)"
></app-message-button>
<app-message-button
[text]="'System'"
[type]="MESSAGE.SYSTEM"
[active]="activeButton == MESSAGE.SYSTEM"
(messageType)="onFilter($event)"
></app-message-button>
</div>
import { Component, OnInit, Output, EventEmitter, Input } from "@angular/core";
@Component({
selector: "app-message-button",
templateUrl: "./message-button.component.html",
styleUrls: ["./message-button.component.scss"]
})
export class MessageButtonComponent implements OnInit {
@Input() type: String;
@Input() text: String;
@Input() active: boolean;
@Output() messageType = new EventEmitter<String>();
constructor() {}
ngOnInit() {}
filter() {
this.messageType.emit(this.type);
}
}
import { Component, OnInit, Output, EventEmitter, Input } from "@angular/core";
@Component({
selector: "app-message-button",
templateUrl: "./message-button.component.html",
styleUrls: ["./message-button.component.scss"]
})
export class MessageButtonComponent implements OnInit {
@Input() type: String;
@Input() text: String;
@Input() active: boolean;
@Output() messageType = new EventEmitter<String>();
constructor() {}
ngOnInit() {}
filter() {
this.messageType.emit(this.type);
}
}
my app-message-button like that :
<button [ngClass]="{ active: active == true }" (click)="filter()" type="button">
{{ text }}
</button>
import { Component, OnInit, Output, EventEmitter, Input } from "@angular/core";
import { MESSAGE } from "@core/constant/constant";
@Component({
selector: "app-message-button-menu",
templateUrl: "./message-button-menu.component.html",
styleUrls: ["./message-button-menu.component.scss"]
})
export class MessageButtonMenuComponent implements OnInit {
MESSAGE;
activeButton: String;
@Output() filter = new EventEmitter<String>();
constructor() {}
ngOnInit(): void {
this.MESSAGE = MESSAGE;
this.activeButton = MESSAGE.ALL;
}
onFilter(type: String) {
this.activeButton = type;
this.filter.emit(type);
}
}
and here is my app-message-chat :
<ul>
<app-message-item
*ngFor="let message of messages; trackBy: trackBy"
[message]="message"
></app-message-item>
</ul>
import { Component, OnInit, Input } from "@angular/core";
import { Message } from "@core/models/message";
@Component({
selector: "app-message-chat",
templateUrl: "./message-chat.component.html",
styleUrls: ["./message-chat.component.scss"]
})
export class MessageChatComponent implements OnInit {
@Input("messages") messages: Message[];
constructor() {}
ngOnInit(): void {}
trackBy(index: number, item: Message): Message {
return item;
}
}
EDIT Ling Vu Answer work :
import { Message } from "@core/models/message";
import { Injectable } from "@angular/core";
import { MESSAGE } from "@core/constant/constant";
import { ReplaySubject } from "rxjs";
@Injectable({
providedIn: "root"
})
export class MessageService {
messages: Message[] = [];
filteredMessages: ReplaySubject<Message[]> = new ReplaySubject(1);
filter: String;
private add(message: String, type: string) {
this.messages.push(new Message(message, type));
this.filterMessages();
}
addGeneralMessage(message: String) {
this.add(message, MESSAGE.GENERAL);
}
addCombatMessage(message: String) {
this.add(message, MESSAGE.COMBAT);
}
clear() {
this.messages = [];
}
setFilter(filter: String) {
this.filter = filter;
}
filterMessages() {
if (!this.filteredMessages)
this.filteredMessages = new ReplaySubject(1);
if (this.filter === MESSAGE.ALL) {
this.filteredMessages.next(this.messages);
} else {
this.filteredMessages.next(
this.messages.filter(item => item.type === this.filter)
);
}
}
constructor() {}
}
my message component :
export class MessageComponent implements OnInit {
messages: Message[];
constructor(public messageService: MessageService) {}
ngOnInit() {
this.messageService.setFilter(MESSAGE.ALL);
this.messageService.filteredMessages.subscribe(
messages => (this.messages = messages)
);
}
filterByType(type: String) {
this.messageService.setFilter(type);
if (type === MESSAGE.ALL) {
this.messages = this.messageService.messages;
} else {
this.messages = this.messageService.messages.filter(
messages => messages.type === type
);
}
}
}
sadly I didn't find how to implement Observable property in my component as he told me. I will find some lessons
Thank you Ling Vu