Skip to content

Utility pipes

@flyze/lib-core-angular 1.0.0-alpha.34· latest

Four small pipes, all declared and exported by PipesModule (pipes.module.ts):

PipePurpose
safeHtmlrender a string as HTML
safeResourceUrluse a string as an iframe / embed source
filterfilter objects by one property
advancedFilterfilter objects by a full-text search

All four are pure, so they re-run only when their input reference changes. Filtering a list that is mutated in place does not update — replace the array.

The translation pipes are separate; see translate-pipes.

safeHtml / safeResourceUrl — sanitizer bypass

Section titled “safeHtml / safeResourceUrl — sanitizer bypass”

Both call DomSanitizer.bypassSecurityTrust* (safe-html.pipe.ts:14, safe-resource-url.pipe.ts:14). They do not sanitize anything — the name says “safe” in Angular’s sense of “trusted”, which is the opposite of validated.

<div [innerHTML]="content | safeHtml"></div>

Anything piped through them executes. safeHtml on attacker-influenced input is an XSS vulnerability: Angular’s sanitizer is the thing that would have stripped the <script> or the onerror=, and these pipes exist purely to switch it off. safeResourceUrl is the same for javascript: URLs in an <iframe src>.

Only use them for values the application itself produced. For anything that reached the app from a user, an API or a URL, bind [innerHTML] without the pipe — Angular sanitizes it and keeps the markup you actually wanted.

<li *ngFor="let user of users | filter: search : 'name'"></li>

Case-insensitive substring match on one property; the property defaults to 'label' (filter.pipe.ts:7). An empty or falsy search term returns the list unchanged, which is what makes it usable while typing.

Limitation: the value is read and lower-cased with no guard (filter.pipe.ts:14), so any item where the property is missing, null, or not a string throws TypeError: … .toLowerCase is not a function and takes the whole view down. Only use it on a list where every item has that property as a string.

<li *ngFor="let user of users | advancedFilter: search"></li>

Keeps every item that contains the search text anywhere — it walks strings, arrays and nested objects recursively (advanced-filter.pipe.ts:48). Unlike filter it is defensive: a non-array input returns [], an empty search term returns the input, and non-string leaves are skipped instead of throwing.

The logic lives in static methods (filterArrayByString, searchInObj, searchInArray, searchInString), so it is reusable from TypeScript without the pipe:

AdvancedFilterPipe.filterArrayByString(users, 'peter');

Worth knowing:

  • The third argument is ignored. transform(mainArr, searchText, property) never passes property on (advanced-filter.pipe.ts:13) — it is always a full-object search. Use filter to restrict the search to one property.
  • Numbers, booleans and dates do not match. Only string leaves are compared (advanced-filter.pipe.ts:59), so searching "42" never finds { count: 42 }.
  • A cyclic object graph recurses until the stack overflows — there is no visited set.
  • Cost is the whole object tree per item per keystroke; for large lists filter in the component instead.

The /pipe-test route of the test app covers safeHtml; neither filter pipe has a playground yet.