Фильтруйте массив и продолжайте получать данные - PullRequest
0 голосов
/ 03 марта 2020

Я пытаюсь построить простую ролевую игру, используя Angular. У меня есть консольный журнал, отображающий такие события, как Damage Dealt / Experience заработал.

У меня есть вызов службы MessageService, где у меня есть свойство массива типа Message (текст, дата, тип).

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() {}
}

У меня есть кнопки в журнале консоли, позволяющие пользователю «фильтровать» все сообщения, чтобы получить только указанный тип c (Бой / Общий / Система).

Я могу фильтровать, используя: messages.filter (message => message.type == type), что я не могу сделать, так это продолжать получать новое сообщение выбранного типа.

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
            );
        }
    }
}

Есть идеи? Я попытался использовать observable, но безуспешно. Думаю, у меня не получилось хорошо его реализовать.

РЕДАКТИРОВАТЬ: Мой компонент сообщения выглядит следующим образом:

<div class="log">
    <app-message-button-menu
        (filter)="filterByType($event)"
    ></app-message-button-menu>
    <app-message-chat [messages]="messages"></app-message-chat>
</div>

мой app-message-button-menu вроде что:

<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);
    }
}

моя кнопка-сообщение-приложение вот так:

<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);
    }
}

и вот мой-чат-приложение:

<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;
    }
}

РЕДАКТИРОВАТЬ Линг Vu Ответ работы:

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() {}
}

мой компонент сообщения:

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
            );
        }
    }
}

к сожалению, я не нашел, как реализовать свойство Observable в моем компоненте, как он сказал мне. Я найду несколько уроков

Спасибо, Лин Ву

Ответы [ 2 ]

1 голос
/ 03 марта 2020

Примените наблюдаемое так:

MessageService

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[] = [];
    filteredMessages: ReplaySubject<Message[]>;
    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 (!filteredMessages) filteredMessages = new ReplaySubject(1);

        this.filteredMessages.next(this.messageService.messages.filter(
             item => item.type === this.filter
        ));
    }
    constructor() {}
}

и подпишитесь на него в компоненте. Ваш атрибут в компоненте должен быть Observable<Message[]>. После этого вы можете использовать его с * ngIf и async pipe

0 голосов
/ 03 марта 2020

Итак, прежде всего, в последнее время мне пришлось сосредоточиться на react, и я не могу привести примеры, которые следуют передовым методам.

Тем не менее, приведенный ниже пример должен дать вам работающее приложение. Да, и еще одна вещь, используйте тип string, а не String Машинопись: разница между строкой и строкой .

Служба сообщений:

import {Injectable} from '@angular/core';
import {Message} from './message';
import {MESSAGE_TYPE} from './messageType'

@Injectable()
export class MessageService {
  public messages: Message[] = [
    {message: 'general', type: MESSAGE_TYPE.GENERAL},
    {message: 'general1', type: MESSAGE_TYPE.GENERAL},
    {message: 'general2', type: MESSAGE_TYPE.GENERAL},
    {message: 'general3', type: MESSAGE_TYPE.GENERAL},
    {message: 'combat', type: MESSAGE_TYPE.COMBAT},
    {message: 'combat1', type: MESSAGE_TYPE.COMBAT},
    {message: 'combat2', type: MESSAGE_TYPE.COMBAT},
    {message: 'combat3', type: MESSAGE_TYPE.COMBAT},
  ];

  private add(message: string, type: MESSAGE_TYPE): void {
    this.messages.push({message, type});
  }
  public addGeneralMessage(message: string): void {
    this.add(message, MESSAGE_TYPE.GENERAL);
  }
  public addCombatMessage(message: string): void {
    this.add(message, MESSAGE_TYPE.COMBAT);
  }
  public clear(): void {
    this.messages = [];
  }
  constructor() {}
}

Приложение Компонент ts

import {Component, OnInit} from '@angular/core';

import {MessageService} from './message.service';
import {Message} from './message';
import {MESSAGE_TYPE} from './messageType';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
  name = 'Angular';
  // "Exporting" enum so it's available in the HTML.
  // This is probably not the right way if your way is working, keep it that way.
  // I haven't written angular in a long time (had to do react) and so I can't tell you
  // best practices.
  public MESSAGE_TYPE = MESSAGE_TYPE;

  public messages: Message[] = [];
  public selectedType: MESSAGE_TYPE = MESSAGE_TYPE.GENERAL;

  public constructor(public messageService: MessageService) {}

  public ngOnInit() {
    this.goAndFilter();
  }

  public filterMessages(type: MESSAGE_TYPE) {
    this.selectedType = type;
    this.goAndFilter();
  }

  // really creative I know
  private goAndFilter(): void {
    this.messages = this.messageService.messages.filter(_ => _.type === this.selectedType);
  }
}

Компонент приложения html

<p>Selected type: {{selectedType}}<P>

<Button 
  (click)="filterMessages(MESSAGE_TYPE.COMBAT)"
>Show Combat</Button>
<Button 
  (click)="filterMessages(MESSAGE_TYPE.GENERAL)"
>Show General</Button>

<div *ngFor="let message of messages">
  <p>{{message.message}} - {{message.type}}</p>
</div>

Вот StackBlitz, но я не знаю, является ли это постоянным: https://stackblitz.com/edit/angular-vwpi6n?file=src%2Fapp%2Fapp.component.html.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...