π
#angular #decorators #services
β Article link: https://javascript.plainenglish.io/advanced-dependency-handling-techniques-the-power-of-self-and-optional-in-angular-dependency-f30db727897a
@Self and @Optional in Angular Dependency Injection#angular #decorators #services
β Article link: https://javascript.plainenglish.io/advanced-dependency-handling-techniques-the-power-of-self-and-optional-in-angular-dependency-f30db727897a
π Angular Input Value Transform
#angular #input #transform
β οΈ This feature has been available since version 16.1
π© > Angular v16.1
β Article link: https://kevinkreuzer.medium.com/angular-input-transform-3a6881902342
#angular #input #transform
β οΈ This feature has been available since version 16.1
π© > Angular v16.1
β Article link: https://kevinkreuzer.medium.com/angular-input-transform-3a6881902342
π1
π
#angular #guard #keycloak #mapToCanActivate
π© > Angular v16
Add the guard function to your routeβs canActivate property.
β οΈ Using mapToCanActivate Helper
If youβre not ready to fully migrate to functional guards, Angular 16 provides a helper function,
β Article link: https://medium.com/@kapincev/migrating-keycloakauthguard-to-angular-16-functional-guards-01bf2a20fc09
KeycloakAuthGuard in Angular#angular #guard #keycloak #mapToCanActivate
π© > Angular v16
Add the guard function to your routeβs canActivate property.
// In your routing module
{
path: 'protected-route',
canActivate: [keycloakFunctionalGuard],
component: ProtectedComponent
}
β οΈ Using mapToCanActivate Helper
If youβre not ready to fully migrate to functional guards, Angular 16 provides a helper function,
mapToCanActivate, that allows you to continue using your class-based guards.{
path: 'protected-route',
canActivate: mapToCanActivate([wrappedAuthGuard]),
component: ProtectedComponent
}β Article link: https://medium.com/@kapincev/migrating-keycloakauthguard-to-angular-16-functional-guards-01bf2a20fc09
π Custom RxJS operators 1/7: "Π‘ache operator"
#angular #rxjs #cache
Often an RxJS stream represents an http request β a stream that emits a single value and completes. Performance-wise, it is a good practice to cache a response from a server for a certain amount of time. The built-in share operator can be configured to provide a caching mechanism with a Time To Live (TTL) for a response.
operator
#angular #rxjs #cache
Often an RxJS stream represents an http request β a stream that emits a single value and completes. Performance-wise, it is a good practice to cache a response from a server for a certain amount of time. The built-in share operator can be configured to provide a caching mechanism with a Time To Live (TTL) for a response.
operator
import { ... } from 'rxjs';
function cache<T>(ttl: number = Infinity): MonoTypeOperatorFunction<T> {
return share({
connector: () => new ReplaySubject(1),
resetOnComplete: () => timer(ttl),
});
}π₯1
π Custom RxJS operators 2/7: "filterNil operator"
#angular #rxjs #filterNil
It is quite common to filter out null and undefined values from the resulting stream. Obviously, the built-in filter operator is the right tool to do the job, however in order to ensure proper type narrowing, the predicate function has to be a user-defined type guard. Therefore, it makes sense to encapsulate it into a custom RxJS operator.
operator
#angular #rxjs #filterNil
It is quite common to filter out null and undefined values from the resulting stream. Obviously, the built-in filter operator is the right tool to do the job, however in order to ensure proper type narrowing, the predicate function has to be a user-defined type guard. Therefore, it makes sense to encapsulate it into a custom RxJS operator.
operator
import { filter, OperatorFunction } from 'rxjs';
function filterNil<T>(): OperatorFunction<T, NonNullable<T>> {
return filter((v): v is NonNullable<T> => v != undefined);
}π1π₯1
π Custom RxJS operators 3/7: "firstMatching operator"
#angular #rxjs #firstMatching
For most use cases, the task can be accomplished at least in two ways. However, there is a subtle difference when the source stream completes without having emitted a value that meets requirements. The detailed explanation can be found in one of my RxJS hints. The operator in question allows to choose a given strategy to handle such scenario based on the required argument.
operator
#angular #rxjs #firstMatching
For most use cases, the task can be accomplished at least in two ways. However, there is a subtle difference when the source stream completes without having emitted a value that meets requirements. The detailed explanation can be found in one of my RxJS hints. The operator in question allows to choose a given strategy to handle such scenario based on the required argument.
operator
import { of, MonoTypeOperatorFunction, pipe, first, filter, take } from 'rxjs';
function firstMatching<T>(
predicateFn: (v: T) => boolean,
required: boolean = false
): MonoTypeOperatorFunction<T> {
return required ? first(predicateFn) : pipe(filter(predicateFn), take(1));
}π₯1
π Scrolling to a Specific
#angular #QueryList
list.component.html
list.component.ts
β Article link: https://medium.com/@garfunkel61/scrolling-to-a-specific-element-in-angular-ngfor-list-navigating-querylists-with-ease-bba15735b41b
QueryList Element #angular #QueryList
list.component.html
<div
*ngFor="let item of items; let i = index"
#myElement
>
<!-- Content of each item -->
</div>
<button
*ngFor="let item of items; let i = index"
(click)="scrollToElement(i)"
>
Scroll to Element {{i}}
</button>
list.component.ts
@Component({...})
export class MyComponent {
@ViewChildren('myElement')
public elements: QueryList<ElementRef>;
public items = [...]; // Your array of items
scrollToElement(index: number): void {
const list = this.elements.toArray();
const element = list[index].nativeElement;
element.scrollIntoView({ behavior: 'smooth' });
}
}
β Article link: https://medium.com/@garfunkel61/scrolling-to-a-specific-element-in-angular-ngfor-list-navigating-querylists-with-ease-bba15735b41b
π2π₯2
π Custom RxJS operators 4/7: "
#angular #rxjs #withLifecycle
Debugging RxJS code can be a challenge. Fortunately, the built-in tap operator provides a way to track lifecycle events for a stream.
operator
withLifecycle operator"#angular #rxjs #withLifecycle
Debugging RxJS code can be a challenge. Fortunately, the built-in tap operator provides a way to track lifecycle events for a stream.
operator
export function withLifecycle<T>(
streamId: string
): MonoTypeOperatorFunction<T> {
return tap({
subscribe: () => console.log(`[${streamId}]: subscribed`),
unsubscribe: () => console.log(`[${streamId}]: unsubscribed`),
finalize: () => console.log(`[${streamId}]: emitted final value`),
});
}
β€1
π₯1
π Custom RxJS operators 5/7: "
#angular #rxjs #pollWhile
The good old polling mechanism is still quite relevant in applications which rely on data that changes over a period of time. Letβs consider a scenario when an application has to make http requests in a certain time interval until an http response body fulfils a given condition, e.g. analysis status is set to completed. The built-in repeat operator combined with a limiting operator allows to accomplish the goal with a few lines of code.
operator
pollWhile operator"#angular #rxjs #pollWhile
The good old polling mechanism is still quite relevant in applications which rely on data that changes over a period of time. Letβs consider a scenario when an application has to make http requests in a certain time interval until an http response body fulfils a given condition, e.g. analysis status is set to completed. The built-in repeat operator combined with a limiting operator allows to accomplish the goal with a few lines of code.
operator
interface PollWhileConfig<T> {
predicateFn: (v: T) => boolean;
delay: number;
count?: number;
lastOnly?: boolean;
}
function pollWhile<T>({
predicateFn,
delay,
count = Infinity,
lastOnly = false,
}: PollWhileConfig<T>): MonoTypeOperatorFunction<T> {
const limiter = lastOnly
? pipe(
filter((v: T) => !predicateFn(v)),
take(1)
)
: takeWhile(predicateFn, true);
return pipe(repeat({ delay, count }), limiter);
}π₯1
π Custom RxJS operators 6/7: "
#angular #rxjs #retryForStatus
The built-in retry operator allows to resubscribe to the source stream once an error has been thrown. It is possible to make a decision whether or not to retry based on the information contained in the error object. In turn, when it comes to streams that represent an http request, the operator can be configured to call an API again only for certain response statuses.
operator
retryForStatus operator"#angular #rxjs #retryForStatus
The built-in retry operator allows to resubscribe to the source stream once an error has been thrown. It is possible to make a decision whether or not to retry based on the information contained in the error object. In turn, when it comes to streams that represent an http request, the operator can be configured to call an API again only for certain response statuses.
operator
interface ErrorWithStatus extends Error {
status: number;
}
interface RetryForStatusConfig {
retryableStatuses: number[];
delay: number;
count?: number;
}
function retryForStatus<T>({
retryableStatuses,
delay,
count = Infinity,
}: RetryForStatusConfig): MonoTypeOperatorFunction<T> {
return retry({
count,
delay: (err: ErrorWithStatus, retryCount) =>
retryableStatuses.includes(err.status)
? timer(retryCount * delay)
: throwError(() => err),
});
}π₯1
π Custom RxJS operators 7/7: "
#angular #rxjs #toLatestFrom
The built-in
operator
toLatestFrom operator"#angular #rxjs #toLatestFrom
The built-in
withLatestFrom operator allows to add data from supplementary streams to the source stream. However, sometimes the source stream is just a trigger to perform a certain action for which data from supplementary streams is needed. As a result, the array of elements in the output stream contains a dummy first element. A better solution is to neglect the value from the trigger.operator
function toLatestFrom<T, D1>(d1$: ObservableInput<D1>): OperatorFunction<T, D1>;
function toLatestFrom<T, D1, D extends unknown[]>(
d1$: ObservableInput<D1>,
...data$: [...ObservableInputTuple<D>]
): OperatorFunction<T, [D1, ...D]>;
function toLatestFrom<D1, D extends unknown[]>(
d1$: ObservableInput<D1>,
...data$: [...ObservableInputTuple<D>]
) {
return pipe(
withLatestFrom(d1$, ...data$),
map(([_, ...data]) => (data.length === 1 ? data[0] : data))
);
}
π₯1