Skip to content

Commit

Permalink
refactor: fn pipe no longer needs explicit context unless invoking a …
Browse files Browse the repository at this point in the history
…method in another instance.

refactor: fn pipe types are now stricter
  • Loading branch information
Javier Marín committed Oct 12, 2024
1 parent dadf0a4 commit c9875c6
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<!-- Channel list -->
<ul>
@for (channel of channels() | fn:filterChannels:this:filterQuery; track channel.id) {
@for (channel of channels() | fn:filterChannels:filterQuery; track channel.id) {
<li [class.active]="activeChannel && channel.id == activeChannel.id">
<!-- Wait 500ms to enable viewport observer while the component render -->
@if (settings.channelMessagesLoading == MessagesLoading.lazy) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {NgTalkChannelMessageWritingComponent} from "./ng-talk-channel-message-wr
template: `
@switch (message.type) {
@case (MessageType.Text) {
<div class="text-message" [innerHTML]="message | fn:transformContent:this"></div>
<div class="text-message" [innerHTML]="message | fn:transformContent"></div>
}
@case (MessageType.Image) {
<img loading="lazy" style="margin-bottom: 8px" [src]="message.content"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
<!-- Messages -->
@for (message of messages(); track trackMessage($index, message)) {
<!-- Date separator -->
@if (message | fn:isSeparatorVisible:this:messages()[$index - 1]) {
@if (message | fn:isSeparatorVisible:messages()[$index - 1]) {
<div style="clear: both"></div>
<div class="day-separator">
<span>{{ message.date | relativeDate : settings }}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import emojis from './emoji.json';
template: `
<input type="search" [placeholder]="chat.settings.search" [(ngModel)]="searchQuery"/>
<div>
@for (pair of emojis | keyvalue | fn:filter:this:searchQuery; track pair) {
@for (pair of emojis | keyvalue | fn:filter:searchQuery; track pair) {
<span (click)="emojiSelected.emit(pair.value)">{{ pair.value }}</span>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ import {NgTalkChannelComponent} from '../../ng-talk-channel.component';
</div>
<div class="gif-list">
@for (gif of gifs$() | async; track gif) {
<span style="text-align: center" (click)="onGifSelected(gif)"><img loading="lazy" [src]="gif | fn:getGifURL:this:false"/></span>
<span style="text-align: center" (click)="onGifSelected(gif)"><img loading="lazy" [src]="gif | fn:getGifURL:false"/></span>
}
</div>
`,
Expand Down
39 changes: 28 additions & 11 deletions projects/ng-talk/src/lib/pipes/fn.pipe.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,38 @@
import {Pipe, PipeTransform} from '@angular/core';
import {ChangeDetectorRef, EmbeddedViewRef, Inject, Pipe, PipeTransform} from '@angular/core';

// https://stackoverflow.com/questions/67605122/obtain-a-slice-of-a-typescript-parameters-tuple
type ParametersExceptFirst<F> = F extends (arg0: any, ...rest: infer R) => any ? R : never;

/**
* Pipe que permite transformar un valor usando una función, recordando el resultado hasta que el valor cambie.
*
* Si se necesita indicar un contexto, se puede indicar como un array con el objeto y el nombre del método.
*
* Ejemplo: user | fn:[userSvc, 'get']
*
* https://dev.to/this-is-angular/deep-dive-into-angular-pipes-implementation-2g5n
*/
@Pipe({
standalone: true,
name: 'fn',
pure: true,
standalone: true
pure: true
})
export class FnPipe implements PipeTransform {
/**
*@inject (ChangeDetectorRef) prevents:
* NullInjectorError: No provider for EmbeddedViewRef!
*/
constructor(@Inject(ChangeDetectorRef) private readonly _viewRef: EmbeddedViewRef<unknown>) {
}

// A template syntax: {{ templateValue | fn:componentMethodRef:thisArg:fnArgument }}
public transform<P, R>(value: P, fnReference: (arg: P, ...fnArguments: Array<any>) => R, context?: any, ...fnArguments: Array<any>): R {
if (fnArguments.length) {
fnArguments.unshift(value);
return fnReference.apply(context, fnArguments);
} else if (context) {
return fnReference.call(context, value);
public transform<T extends (...args: any) => any>(value: Parameters<T>[0], fn: T, ...args: [...ParametersExceptFirst<T>]): ReturnType<T> {
if (args.length) {
args.unshift(value);
return fn.apply(this._viewRef.context, args);
} else {
return fnReference(value);
return fn.call(this._viewRef.context, value);
}
}
}


0 comments on commit c9875c6

Please sign in to comment.