2 Answer(s)
-
0
- In ABP Angular, validation errors (and other HTTP errors) are typically shown via the theme’s HTTP error handler (uses
ConfirmationService.error(...)internally). If your server returns an error message that contains HTML, the safest approach is to override the HTTP error handler and force the message to be treated as plain text (i.e., never bind it as HTML / never pass a “safeHtml” object). - Concretely: register your own
HTTP_ERROR_HANDLERand sanitize/escape the message before showing it.
// error.handler.ts import { Injector } from '@angular/core'; import { HttpErrorResponse } from '@angular/common/http'; import { throwError } from 'rxjs'; import { ConfirmationService } from '@abp/ng.theme.shared'; // Minimal HTML escaping (renders tags as text) function escapeHtml(input: any): string { const s = String(input ?? ''); return s .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } export function handleHttpErrors(injector: Injector, httpError: HttpErrorResponse) { // Example: specifically handle 400 validation errors if (httpError?.status === 400 && httpError.error?.error?.validationErrors?.length) { const confirmationService = injector.get(ConfirmationService); const rawMessage = httpError.error.error.validationErrors[0].message; const rawTitle = httpError.error.error.message; return confirmationService.error( escapeHtml(rawMessage), // prevent HTML injection escapeHtml(rawTitle), // prevent HTML injection { hideCancelBtn: true, yesText: 'AbpAccount::Close' } ); } return throwError(() => httpError); }// app.module.ts import { HTTP_ERROR_HANDLER } from '@abp/ng.theme.shared'; import { handleHttpErrors } from './error.handler'; @NgModule({ // ... providers: [ { provide: HTTP_ERROR_HANDLER, useValue: handleHttpErrors }, ], }) export class AppModule {}This ensures that even if the backend returns
<b>...</b>/<script>...</script>inside a validation message, it will be displayed as text, not executed/interpreted as HTML.Links (verified):
- https://abp.io/support/questions/5171
- https://github.com/abpframework/abp/blob/360a3395aa0e44fb77574ea7eac745e8ba94b82e/npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts#L19
This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post) - In ABP Angular, validation errors (and other HTTP errors) are typically shown via the theme’s HTTP error handler (uses
-
0
Hi,
The confirmation popup binds the title and the message with
[innerHTML], so HTML that comes inside an error message is rendered as markup. Angular sanitizes it first, so script tags and event handler attributes are dropped and no script runs, but plain tags like<b>,<img>or<a href>still render.If you want the text shown as-is, replace
ConfirmationService(andToasterServiceif you also show toasts) and escape the strings before they reach the template:// text-only-messages.service.ts import { Injectable } from '@angular/core'; import { LocalizationParam } from '@abp/ng.core'; import { Confirmation, ConfirmationService, Toaster, ToasterService } from '@abp/ng.theme.shared'; import { Observable } from 'rxjs'; export function escapeHtml(value: string): string { return value .replace(/&/g, '&') .replace(/</g, '<') .replace(/>/g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } function escapeParam(param: LocalizationParam): LocalizationParam { return typeof param === 'string' ? escapeHtml(param) : param; } @Injectable({ providedIn: 'root' }) export class TextOnlyConfirmationService extends ConfirmationService { override show( message: LocalizationParam, title: LocalizationParam, severity?: Confirmation.Severity, options = {} as Partial<Confirmation.Options>, ): Observable<Confirmation.Status> { return super.show(escapeParam(message), escapeParam(title), severity, { ...options, messageLocalizationParams: options.messageLocalizationParams?.map(escapeHtml), titleLocalizationParams: options.titleLocalizationParams?.map(escapeHtml), }); } } @Injectable({ providedIn: 'root' }) export class TextOnlyToasterService extends ToasterService { // the toast title is bound with {{ }}, only the message goes through innerHTML override show( message: LocalizationParam, title?: LocalizationParam, severity: Toaster.Severity = 'neutral', options = {} as Partial<Toaster.ToastOptions>, ): Toaster.ToasterId { return super.show(escapeParam(message), title, severity, { ...options, messageLocalizationParams: options.messageLocalizationParams?.map(escapeHtml), }); } }Then register them in your app providers (
app.config.ts, orapp.module.tsif you are still on modules):import { ConfirmationService, ToasterService } from '@abp/ng.theme.shared'; import { TextOnlyConfirmationService, TextOnlyToasterService } from './text-only-messages.service'; providers: [ { provide: ConfirmationService, useExisting: TextOnlyConfirmationService }, { provide: ToasterService, useExisting: TextOnlyToasterService }, // ... ];Localization keys and
{0}parameters keep working. One thing to keep in mind: after this change, HTML that your own code passes to a confirmation or a toast on purpose is shown as text too.Thanks
Markdown supported.Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)