Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues primefaces#8647 primefaces#5663 remove message or toast by id #13599

Closed
wants to merge 9 commits into from
15 changes: 14 additions & 1 deletion src/app/components/api/messageservice.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ import { Message } from './message';
export class MessageService {
private messageSource = new Subject<Message | Message[]>();
private clearSource = new Subject<string | null>();
private removeSource = new Subject<{ key: string, value: any }>();

messageObserver = this.messageSource.asObservable();
clearObserver = this.clearSource.asObservable();
removeObserver = this.removeSource.asObservable();
/**
* Inserts single message.
* @param {Message} message - Message to be added.
Expand All @@ -23,7 +25,7 @@ export class MessageService {
}
}
/**
* Insterts new messages.
* Inserts new messages.
* @param {Message[]} messages - Messages to be added.
* @group Method
*/
Expand All @@ -32,6 +34,17 @@ export class MessageService {
this.messageSource.next(messages);
}
}
/**
* Removes single message.
* @param {string} key - Property name of the Message to be removed.
* @param {any} value - Property value of the Message to be removed.
* @group Method
*/
remove(key: string, value: any) {
if (key && value) {
this.removeSource.next({ key, value });
}
}
/**
* Clears the message with the given key.
* @param {string} key - Key of the message to be cleared.
Expand Down
24 changes: 22 additions & 2 deletions src/app/components/messages/messages.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { TestBed, ComponentFixture } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { Messages } from './messages';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { Component, NO_ERRORS_SCHEMA } from '@angular/core';
import { Component } from '@angular/core';
import { Button } from 'primeng/button';
import { FormsModule } from '@angular/forms';
import { MessageService } from 'primeng/api';
Expand All @@ -26,6 +26,7 @@ import { TimesIcon } from 'primeng/icons/times';
<button type="button" pButton (click)="showAllViaService()" label="Use Service"></button>
<button type="button" pButton (click)="clearWithService()" label="Use Service"></button>
<button type="button" pButton (click)="clearWithServiceAndKey()" label="Use Service"></button>
<button type="button" pButton (click)="removeWithServiceAndId()" label="Use Service"></button>
`
})
class TestMessagesComponent {
Expand Down Expand Up @@ -65,7 +66,7 @@ class TestMessagesComponent {
showAllViaService() {
this.messageService.addAll([
{ severity: 'success', key: 'primeng', summary: 'Service Message', detail: 'Via MessageService' },
{ severity: 'success', summary: 'Service Message', detail: 'Via MessageService' }
{ severity: 'success', id: 1, summary: 'Service Message', detail: 'Via MessageService' }
]);
}

Expand All @@ -76,6 +77,10 @@ class TestMessagesComponent {
clearWithServiceAndKey() {
this.messageService.clear('primeng');
}

removeWithServiceAndId() {
this.messageService.remove('id', 1);
}
}

describe('Messages', () => {
Expand Down Expand Up @@ -243,4 +248,19 @@ describe('Messages', () => {
const messageEl = fixture.debugElement.queryAll(By.css('.p-message-icon'));
expect(messageEl.length).toEqual(2);
});

it('should remove with service and id', () => {
fixture.detectChanges();

const successButton = fixture.debugElement.queryAll(By.css('button'))[6];
const removeButton = fixture.debugElement.queryAll(By.css('button'))[9];
successButton.nativeElement.click();
fixture.detectChanges();

removeButton.nativeElement.click();
fixture.detectChanges();

const messageEl = fixture.debugElement.queryAll(By.css('.p-message-icon'));
expect(messageEl.length).toEqual(2);
});
});
14 changes: 14 additions & 0 deletions src/app/components/messages/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ export class Messages implements AfterContentInit, OnDestroy {

messageSubscription: Subscription | undefined;

removeSubscription: Subscription | undefined;

clearSubscription: Subscription | undefined;

timerSubscriptions: Subscription[] = [];
Expand Down Expand Up @@ -172,6 +174,14 @@ export class Messages implements AfterContentInit, OnDestroy {
}
});

this.removeSubscription = this.messageService.removeObserver.subscribe((property: { key: string, value: any }) => {
if (property.key && property.value) {
this.messages = this.messages ? this.messages.filter(m => m[property.key] !== property.value) : this.messages;
}

this.cd.markForCheck();
});

this.clearSubscription = this.messageService.clearObserver.subscribe((key) => {
if (key) {
if (this.key === key) {
Expand Down Expand Up @@ -235,6 +245,10 @@ export class Messages implements AfterContentInit, OnDestroy {
this.messageSubscription.unsubscribe();
}

if (this.removeSubscription) {
this.removeSubscription.unsubscribe();
}

if (this.clearSubscription) {
this.clearSubscription.unsubscribe();
}
Expand Down
43 changes: 43 additions & 0 deletions src/app/components/toast/toast.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class TestToastComponent {
this.messageService.add({ key: key, severity: 'warn', summary: 'Are you sure?', detail: 'Confirm to proceed' });
}

showWithId(id) {
this.messageService.add({ id: id, severity: 'warn', summary: 'Are you sure?', detail: 'Confirm to proceed' });
}

showMultipleToast() {
this.messageService.addAll([
{ severity: 'warn', summary: 'Are you sure?', detail: 'Confirm to proceed' },
Expand All @@ -34,6 +38,10 @@ class TestToastComponent {
this.messageService.clear(key);
}

onClearWithId(key, value) {
this.messageService.remove(key, value);
}

onClear() {
this.messageService.clear();
}
Expand Down Expand Up @@ -106,6 +114,17 @@ describe('Toast', () => {
expect(toastMessage.nativeElement.classList).toContain('p-toast-message-warn');
});

it('should create warn toast with id', () => {
fixture.detectChanges();

component.showWithId(1);
fixture.detectChanges();

let toastMessage = fixture.debugElement.query(By.css('.p-toast-message'));
expect(toastMessage.nativeElement).toBeTruthy();
expect(toastMessage.nativeElement.classList).toContain('p-toast-message-warn');
});

it('should clear toast', () => {
fixture.detectChanges();

Expand Down Expand Up @@ -143,6 +162,30 @@ describe('Toast', () => {
});
});

it('should clear toast with id', () => {
fixture.detectChanges();

component.showDefaultToast('success');
component.showWithId(1);
fixture.detectChanges();

let toastMessages = fixture.debugElement.queryAll(By.css('.p-toast-message'));
expect(toastMessages.length).toBe(2);
expect(toastMessages[0].nativeElement).toBeTruthy();
expect(toastMessages[0].nativeElement.classList).toContain('p-toast-message-success');
expect(toastMessages[1].nativeElement).toBeTruthy();
expect(toastMessages[1].nativeElement.classList).toContain('p-toast-message-warn');
component.onClearWithId('id', 1);
fixture.detectChanges();

Promise.resolve(null).then(() => {
toastMessages = fixture.debugElement.queryAll(By.css('.p-toast-message'));
expect(toastMessages.length).toBe(1);
expect(toastMessages[0].nativeElement).toBeTruthy();
expect(toastMessages[0].nativeElement.classList).toContain('p-toast-message-success');
});
});

it('should create multiple toast', () => {
fixture.detectChanges();

Expand Down
14 changes: 14 additions & 0 deletions src/app/components/toast/toast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,8 @@ export class Toast implements OnInit, AfterContentInit, OnDestroy {

messageSubscription: Subscription | undefined;

removeSubscription: Subscription | undefined;

clearSubscription: Subscription | undefined;

messages: Message[] | null | undefined;
Expand All @@ -326,6 +328,14 @@ export class Toast implements OnInit, AfterContentInit, OnDestroy {
}
});

this.removeSubscription = this.messageService.removeObserver.subscribe((property: { key: string, value: any }) => {
if (property.key && property.value) {
this.messages = this.messages ? this.messages.filter(m => m[property.key] !== property.value) : this.messages;
}

this.cd.markForCheck();
});

this.clearSubscription = this.messageService.clearObserver.subscribe((key) => {
if (key) {
if (this.key === key) {
Expand Down Expand Up @@ -462,6 +472,10 @@ export class Toast implements OnInit, AfterContentInit, OnDestroy {
ZIndexUtils.clear(this.containerViewChild.nativeElement);
}

if (this.removeSubscription) {
this.removeSubscription.unsubscribe();
}

if (this.clearSubscription) {
this.clearSubscription.unsubscribe();
}
Expand Down
19 changes: 15 additions & 4 deletions src/app/showcase/doc/messages/servicedoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { Code } from '../../domain/code';
<div class="flex justify-content-center gap-2">
<button type="button" pButton class="p-button-primary" (click)="addSingle()" label="Show Single"></button>
<button type="button" pButton class="p-button-success" (click)="addMultiple()" label="Show Multiple"></button>
<button type="button" pButton class="p-button-warning" (click)="remove('id', 1)" label="Remove Single"></button>
<button type="button" pButton class="p-button-secondary" (click)="clear()" label="Clear All"></button>
</div>
<p-messages></p-messages>
Expand All @@ -36,11 +37,15 @@ export class ServiceDoc {

addMultiple() {
this.messageService.addAll([
{ severity: 'success', summary: 'Service Message', detail: 'Via MessageService' },
{ severity: 'info', summary: 'Info Message', detail: 'Via MessageService' }
{ id: 1, severity: 'success', summary: 'Service Message', detail: 'Via MessageService' },
{ id: 2, severity: 'info', summary: 'Info Message', detail: 'Via MessageService' }
]);
}

remove(key: string, value: any) {
this.messageService.remove(key, value);
}

clear() {
this.messageService.clear();
}
Expand All @@ -50,6 +55,7 @@ export class ServiceDoc {
<div class="flex justify-content-center gap-2">
<button type="button" pButton class="p-button-primary" (click)="addSingle()" label="Single"></button>
<button type="button" pButton class="p-button-success" (click)="addMultiple()" label="Multiple"></button>
<button type="button" pButton class="p-button-warning" (click)="remove('id', 1)" label="Remove"></button>
<button type="button" pButton class="p-button-secondary" (click)="clear()" label="Clear"></button>
</div>
<p-messages></p-messages>`,
Expand All @@ -58,6 +64,7 @@ export class ServiceDoc {
<div class="flex justify-content-center gap-2">
<button type="button" pButton class="p-button-primary" (click)="addSingle()" label="Single"></button>
<button type="button" pButton class="p-button-success" (click)="addMultiple()" label="Multiple"></button>
<button type="button" pButton class="p-button-warning" (click)="remove('id', 1)" label="Remove"></button>
<button type="button" pButton class="p-button-secondary" (click)="clear()" label="Clear"></button>
</div>
<p-messages></p-messages>
Expand All @@ -80,10 +87,14 @@ export class MessagesServiceDemo {

addMultiple() {
this.messageService.addAll([
{severity:'success', summary:'Service Message', detail:'Via MessageService'},
{severity:'info', summary:'Info Message', detail:'Via MessageService'}
{ id: 1, severity: 'success', summary: 'Service Message', detail: 'Via MessageService' },
{ id: 2, severity: 'info', summary: 'Info Message', detail: 'Via MessageService' }
]);
}

remove(key: string, value: any) {
this.messageService.remove(key, value);
}

clear() {
this.messageService.clear();
Expand Down
75 changes: 75 additions & 0 deletions src/app/showcase/doc/toast/removedoc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { Component, Input } from '@angular/core';
import { MessageService } from 'primeng/api';
import { Code } from '../../domain/code';

@Component({
selector: 'remove-doc',
template: ` <section>
<app-docsectiontext [title]="title" [id]="id">
<p>
A toast may be removed programmatically by any property <i>key</i> and corresponding <i>value</i>.
</p>
</app-docsectiontext>
<div class="card flex justify-content-center gap-2">
<p-toast key="myKey"></p-toast>
<button type="button" pButton pRipple (click)="show()" label="Show"></button>
<button type="button" pButton pRipple (click)="remove('id', 1)" label="Remove" class="p-button-secondary"></button>
</div>
<app-code [code]="code" selector="toast-remove-demo"></app-code>
</section>`,
providers: [MessageService]
})
export class RemoveDoc {
@Input() id: string;

@Input() title: string;

constructor(private messageService: MessageService) {}

show() {
this.messageService.addAll([
{ id: 1, key: 'myKey', severity: 'success', summary: 'Message 1', detail: 'Message Content', life: 60000 },
{ id: 2, key: 'myKey', severity: 'success', summary: 'Message 2', detail: 'Message Content', life: 60000 }
]);
}

remove(key: string, value: any) {
this.messageService.remove(key, value);
}

code: Code = {
basic: `
<p-toast></p-toast>
<button type="button" pButton pRipple (click)="show()" label="Show"></button>
<button type="button" pButton pRipple (click)="remove('id', 1)" label="Remove" class="p-button-secondary"></button>`,
html: `
<div class="card flex justify-content-center gap-2">
<p-toast></p-toast>
<button type="button" pButton pRipple (click)="show()" label="Show"></button>
<button type="button" pButton pRipple (click)="remove('id', 1)" label="Remove" class="p-button-secondary"></button>
</div>`,
typescript: `
import { Component } from '@angular/core';
import { MessageService } from 'primeng/api';

@Component({
selector: 'toast-remove-demo',
templateUrl: './toast-remove-demo.html',
providers: [MessageService]
})
export class ToastRemoveDemo {
constructor(private messageService: MessageService) {}

show() {
this.messageService.addAll([
{ id: 1, key: 'myKey', severity: 'success', summary: 'Message 1', detail: 'Message Content', life: 60000 },
{ id: 2, key: 'myKey', severity: 'success', summary: 'Message 2', detail: 'Message Content', life: 60000 }
]);
}

remove(key: string, value: any) {
this.messageService.remove(key, value);
}
}`
};
}
3 changes: 2 additions & 1 deletion src/app/showcase/doc/toast/toastdoc.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ import { StyleDoc } from './styledoc';
import { TargetDoc } from './targetdoc';
import { TemplateDoc } from './templatedoc';
import { ClearDoc } from './cleardoc';
import { RemoveDoc } from './removedoc';
import { AccessibilityDoc } from './accessibilitydoc';

@NgModule({
imports: [CommonModule, RouterModule, AppCodeModule, AppDocModule, ToastModule, ButtonModule, RippleModule],
declarations: [AnimationDoc, BasicDoc, ImportDoc, MultipleDoc, PositionDoc, ResponsiveDoc, SeverityDoc, LifeDoc, StickyDoc, StyleDoc, TargetDoc, TemplateDoc, ClearDoc, AccessibilityDoc],
declarations: [AnimationDoc, BasicDoc, ImportDoc, MultipleDoc, PositionDoc, ResponsiveDoc, SeverityDoc, LifeDoc, StickyDoc, StyleDoc, TargetDoc, TemplateDoc, ClearDoc, RemoveDoc, AccessibilityDoc],
exports: [AppDocModule]
})
export class ToastDocModule {}
Loading