Skip to content

Commit 2feebb4

Browse files
committed
feat: add option to display message as HTML
1 parent f669811 commit 2feebb4

File tree

12 files changed

+105
-7
lines changed

12 files changed

+105
-7
lines changed

docusaurus/docs/Angular/components/ChannelPreviewComponent.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ The `ChannelPreview` component displays a channel preview in the channel list, i
44

55
The channel list uses the `ChannelPreview` component to display channels, if you want to replace that with your own custom component you can use the [`CustomTemplatesService`](../services/CustomTemplatesService.mdx/#channelpreviewtemplate).
66

7+
The [`MessageService`](../services/MessageService.mdx) has additional customization options.
8+
79
:::note
810

911
If you want to build your own `ChannelPreview` component, you might find the following building blocks useful:

docusaurus/docs/Angular/components/MessageComponent.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ The message list uses the `Message` component to display messages, if you want t
2222

2323
The `Message` component uses the [`DateParserService`](../services/DateParserService.mdx) to create user-friendly dates, you can override the date-parsing methods with your own functions.
2424

25+
The [`MessageService`](../services/MessageService.mdx) has additional customization options.
26+
2527
:::note
2628

2729
If you want to build your own `Message` component, you might find the following building blocks useful:

projects/sample-app/src/app/app.component.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
CustomTemplatesService,
1515
ThemeService,
1616
AvatarContext,
17+
MessageService,
1718
} from 'stream-chat-angular';
1819
import { environment } from '../environments/environment';
1920

@@ -37,8 +38,10 @@ export class AppComponent implements AfterViewInit {
3738
private channelService: ChannelService,
3839
private streamI18nService: StreamI18nService,
3940
private customTemplateService: CustomTemplatesService,
40-
themeService: ThemeService
41+
themeService: ThemeService,
42+
messageService: MessageService
4143
) {
44+
messageService.displayAs = 'html';
4245
void this.chatService.init(
4346
environment.apiKey,
4447
environment.userId,

projects/stream-chat-angular/src/lib/channel-preview/channel-preview.component.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@
3737
data-testid="latest-message"
3838
class="str-chat__channel-preview-messenger--last-message"
3939
>
40-
{{ latestMessage | translate }}
40+
<ng-container *ngIf="displayAs === 'text'; else asHTML">
41+
{{ latestMessage | translate }}
42+
</ng-container>
43+
<ng-template #asHTML>
44+
<span
45+
data-testid="html-content"
46+
[innerHTML]="latestMessage | translate"
47+
></span>
48+
</ng-template>
4149
</div>
4250
</div>
4351
</button>

projects/stream-chat-angular/src/lib/channel-preview/channel-preview.component.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,4 +328,21 @@ describe('ChannelPreviewComponent', () => {
328328

329329
expect(queryLatestMessage()?.textContent).toContain('Hogy vagy?');
330330
});
331+
332+
it('should respect #displayAs setting', () => {
333+
const channel = generateMockChannels()[0];
334+
component.channel = channel;
335+
fixture.detectChanges();
336+
337+
expect(nativeElement.querySelector('[data-testid="html-content"]')).toBe(
338+
null
339+
);
340+
341+
component.displayAs = 'html';
342+
fixture.detectChanges();
343+
344+
expect(
345+
nativeElement.querySelector('[data-testid="html-content"]')
346+
).not.toBe(null);
347+
});
331348
});

projects/stream-chat-angular/src/lib/channel-preview/channel-preview.component.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { getChannelDisplayText } from '../get-channel-display-text';
1111
import { DefaultStreamChatGenerics } from '../types';
1212
import { ChatClientService } from '../chat-client.service';
1313
import { getMessageTranslation } from '../get-message-translation';
14+
import { MessageService } from '../message.service';
1415

1516
/**
1617
* The `ChannelPreview` component displays a channel preview in the channel list, it consists of the image, name and latest message of the channel.
@@ -29,14 +30,18 @@ export class ChannelPreviewComponent implements OnInit, OnDestroy {
2930
isUnread = false;
3031
unreadCount: number | undefined;
3132
latestMessage: string = 'streamChat.Nothing yet...';
33+
displayAs: 'text' | 'html';
3234
private subscriptions: (Subscription | { unsubscribe: () => void })[] = [];
3335
private canSendReadEvents = true;
3436

3537
constructor(
3638
private channelService: ChannelService,
3739
private ngZone: NgZone,
38-
private chatClientService: ChatClientService
39-
) {}
40+
private chatClientService: ChatClientService,
41+
messageService: MessageService
42+
) {
43+
this.displayAs = messageService.displayAs;
44+
}
4045

4146
ngOnInit(): void {
4247
this.subscriptions.push(
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TestBed } from '@angular/core/testing';
2+
3+
import { MessageService } from './message.service';
4+
5+
describe('MessageService', () => {
6+
let service: MessageService;
7+
8+
beforeEach(() => {
9+
TestBed.configureTestingModule({});
10+
service = TestBed.inject(MessageService);
11+
});
12+
13+
it('should be created', () => {
14+
expect(service).toBeTruthy();
15+
});
16+
});
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Injectable } from '@angular/core';
2+
3+
/**
4+
* The message service contains configuration options related to displaying the message content
5+
*/
6+
@Injectable({
7+
providedIn: 'root',
8+
})
9+
export class MessageService {
10+
/**
11+
* Decides if the message content should be formatted as text or HTML
12+
*/
13+
displayAs: 'text' | 'html' = 'text';
14+
15+
constructor() {}
16+
}

projects/stream-chat-angular/src/lib/message/message.component.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,15 @@
261261
</ng-container>
262262
</ng-container>
263263
<ng-template #defaultContent>
264-
{{ messageText || "" }}
264+
<ng-container *ngIf="displayAs === 'text'; else asHTML">
265+
{{ messageText || "" }}
266+
</ng-container>
267+
<ng-template #asHTML
268+
><span
269+
data-testid="html-content"
270+
[innerHTML]="messageText"
271+
></span
272+
></ng-template>
265273
</ng-template>
266274
</p>
267275
</div>

projects/stream-chat-angular/src/lib/message/message.component.spec.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { ChatClientService } from '../chat-client.service';
1313
import { IconComponent } from '../icon/icon.component';
1414
import { MessageActionsBoxComponent } from '../message-actions-box/message-actions-box.component';
1515
import { By } from '@angular/platform-browser';
16-
import { mockCurrentUser, mockMessage } from '../mocks';
16+
import { generateMockMessages, mockCurrentUser, mockMessage } from '../mocks';
1717
import { AttachmentListComponent } from '../attachment-list/attachment-list.component';
1818
import { MessageReactionsComponent } from '../message-reactions/message-reactions.component';
1919
import { TranslateModule } from '@ngx-translate/core';
@@ -1238,5 +1238,21 @@ describe('MessageComponent', () => {
12381238

12391239
expect(queryTranslationNotice()).toBeNull();
12401240
});
1241+
1242+
it('should respect #displayAs setting', () => {
1243+
component.message = generateMockMessages()[0];
1244+
fixture.detectChanges();
1245+
1246+
expect(nativeElement.querySelector('[data-testid="html-content"]')).toBe(
1247+
null
1248+
);
1249+
1250+
component.displayAs = 'html';
1251+
fixture.detectChanges();
1252+
1253+
expect(
1254+
nativeElement.querySelector('[data-testid="html-content"]')
1255+
).not.toBe(null);
1256+
});
12411257
});
12421258
});

0 commit comments

Comments
 (0)