Showing posts with label angular. Show all posts
Showing posts with label angular. Show all posts

Tuesday, 13 August 2024

new @let block in Angular templates



<div>
@let userName = (userName$ | async) ?? 'Guest'; <h1>Welcome, {{ userName }}</h1> </div>


<table mat-table [dataSource]="dataSource">
@for (columnDef of columnDefs) {
@let property = columnDef.propertyName;
<ng-container [matColumnDef]="columnDef.name">
<th mat-header-cell *matHeaderCellDef>{{ columnDef.header }}</th>
<td mat-cell *matCellDef="let element">
@let cellValue = element[property];
<ng-container *ngIf="columnDef.cellType === 'link'; else plainCell">
<a [routerLink]="cellValue?.routerLink">{{ cellValue?.value }}</a>
</ng-container>
<ng-template #plainCell>{{ cellValue }}</ng-template>
</td>
</ng-container>
}
</table>



<div>
@let firstName = user?.firstName;
@let lastName = user?.lastName;
@let fullName = `${firstName} ${lastName}`;
<p>{{ fullName }}</p>
@if (user?.address) {
@let street = user.address.street;
@let city = user.address.city;
<p>{{ street }}, {{ city }}</p>
}
</div>


Conclusion 

 @let syntax in Angular, combined with the new control flow features like @if and @for, offers a significant improvement for template variable declarations and control flow management. While some may argue for the continued use of signals for state management, the @let syntax provides an elegant solution for handling local variables within templates. By addressing common challenges such as managing falsy values, avoiding multiple subscriptions, and reducing repetitive code, this new feature is poised to enhance the development experience for Angular developers.


Thursday, 24 November 2022

angular v15 directive ngFor handling empty list

 


// hello.component.ts


import { Component, Input } from '@angular/core';
import { NgForEmpty } from './ng-of-empty';

@Component({
selector: 'hello',
template: `<h1>Hello {{name}}!</h1>
<ul>
<li *ngFor="let p of persons; empty: emptyTmpl">{{p}}</li>
</ul>
<ng-template #emptyTmpl>Empty list</ng-template>
`,
styles: [`h1 { font-family: Lato; }`],
standalone: true,
imports: [NgForEmpty],
})
export class HelloComponent {
@Input() name: string;
persons = ['Dignāga','Dharmakīrti','Kamalaśīla','Śāntarakṣita',
             'Asanga','Vasubandhu'];
}


// ng-of-empty.ts



import { NgFor, NgIf } from '@angular/common';
import { Directive, inject, Input } from '@angular/core';

@Directive({
selector: '[ngFor]',
standalone: true,
hostDirectives: [
{ directive: NgFor, inputs: ['ngForOf'] },
{ directive: NgIf, inputs: ['ngIfElse: ngForEmpty'] },
],
})
export class NgForEmpty<T> {
private readonly ngIf = inject(NgIf, { host: true });

@Input() set ngForOf(ngFor: T[] | undefined) {
this.ngIf.ngIf = ngFor && ngFor.length > 0;
}
}




Sunday, 20 November 2022

Angular functional guard to check on the user role to guard your routes

functional guard to check on the user role  to guard your routes. 


The functional guard accepts a param for the user role 


Less verbose than a class based guard



    use canMatch to skip a route dynamically in combination with functional guards. 

  👍 Super handy when a path should lead to different comp depending on some logic 

  👋 canLoad is going to be deprecated in favor of canMatch


    


Saturday, 19 November 2022

Directive composition API in Angular 15

our directive stand alone by adding standalone property inside directive declaration 

import { Directive } from '@angular/core';

@Directive({
  selector: '[appRedColor]',
  host:{'style': 'color:red;'},
  standalone: true
})
export class RedColorDirective {

  constructor() { }

}

Now the text inside testdirective component will be displayed in red color.

<app-testdirective></app-testdirective>

And our code looks simple without adding an extra directive in component tag.

We can add more than one directive inside hostDirectives property.


@Component({
  selector: 'app-testdirective',
  templateUrl: './testdirective.component.html',
  styleUrls: ['./testdirective.component.scss'],
  hostDirectives:[RedColorDirective,HeightDirective,FontStyleDirective,......]
})
export class TestdirectiveComponent {
}

We can add hostDirectives inside an another directive as well.

Saturday, 15 October 2022

Reusable ng-template with parameters




<ng-template #loading let-overlayHeight="overlayHeight"
let-loaderLeft="loaderLeft" let-marginTop="marginTop">
<div class="overlay" [style.marginTop]="marginTop || ''"
[style.height]="overlayHeight || '100%'" style="position:relative;">
<div class="loader" [style.left]="loaderLeft || '40%'"
        style="position:relative;top:35%">
<svg viewBox="0 0 86 80">
<polygon points="43 8 79 72 7 72"></polygon>
</svg>
</div>
</div>
</ng-template>


Use

<ng-template *ngIf="paretoProductCategoriesChartLoading"
[ngTemplateOutlet]="loading"
[ngTemplateOutletContext]="{overlayHeight: '280px',marginTop:'20px'}">
</ng-template>

Create a common Html element within angular template.

Saturday, 18 June 2022

ng-container with ngTemplateOutlet and ng-template with context variable

<div *ngIf="!multiOptionsChart.length" class="row">
<ng-container *ngTemplateOutlet="
chartBlock;
context: {
optionItem : options,
chartType:'single'
}">
</ng-container>
</div>

<div *ngIf="multiOptionsChart.length" class="row">
<div *ngFor="let optionItem of multiOptionsChart; let i = index">
<ng-container *ngTemplateOutlet="
chartBlock;
context: {
optionItem : optionItem ,
chartType:'multi'
}">
</ng-container>
</div>
</div>

<ng-template #chartBlock
let-optionItem="optionItem"
let-chartType="chartType">

<div class="graph-action">
your multi and single chart type common code
</div>

<ng-container *ngIf="chartType === 'multi'">
<span>chartType</span>
<span>: {{ chartType }}</span>
</ng-container>
<ng-container *ngIf="chartType === 'single'">
<span>single chartType</span>
<span>: {{ chartType }}</span>
</ng-container>
Name : {{ optionItem.name }}
</ng-template>


Tuesday, 31 May 2022

use memo in your angular component template function call

import { Component } from '@angular/core';

function hasDifferentArgs(prev: unknown[], next: unknown[]) {
if (prev.length !== next.length) return true;
for (let i = 0; i < prev.length; i++) {
if (!Object.is(prev[i], next[i])) return true;
}
return false;
}

function memo(fnToMemoize) {
let prevArgs = [{}];
let result;

return function (...newArgs) {
if (hasDifferentArgs(prevArgs, newArgs)) {
result = fnToMemoize(...newArgs);
prevArgs = newArgs;
}
return result;
};
}

function expensiveComputing(name: string) {
return '$' + name + '$';
}

@Component({
selector: 'my-app',
template: 'Hello, {{fancyName(name)}}!',
})
export class AppComponent {
name = 'World';

fancyName = memo((name) => expensiveComputing(name));
}


Wednesday, 24 November 2021

Automatically Unsubscribe in Angular Component


let isFunction = fn => typeof fn === "function";

const doUnsubscribe = subscription => {
subscription &&
isFunction(subscription.unsubscribe) &&
subscription.unsubscribe();
};

const doUnsubscribeIfArray = subscriptionsArray => {
Array.isArray(subscriptionsArray) &&
subscriptionsArray.forEach(doUnsubscribe);
};

export function AutoUnsubscribe({
blackList = [],
arrayName = "",
event = "ngOnDestroy"
} = {}) {
return function(constructor: Function) {
const original = constructor.prototype[event];

if (!isFunction(original)) {
throw new Error(
`${
constructor.name
} is using @AutoUnsubscribe but does not implement ${event}`
);
}

constructor.prototype[event] = function() {
isFunction(original) && original.apply(this, arguments);
if (arrayName) {
doUnsubscribeIfArray(this[arrayName]);
return;
}
for (let propName in this) {
if (blackList.includes(propName)) continue;
const property = this[propName];
doUnsubscribe(property);
}
};
};
} 

//@AutoUnsubscribe() // use if direct property
@AutoUnsubscribe({ // use if you have array of subscriptions
arrayName:"subscriptions"
})
@Component({
selector: 'inbox'
})
export class InboxComponent {
one: Subscription;
two: Subscription;
subscription: [];
constructor( private store: Store<any>, private element : ElementRef ) {}

ngOnInit() {
this.one = store.select("data").subscribe(data => // do something);
this.two = Observable.interval.subscribe(data => // do something);

// this.subscriptions = [
// onResizeSubscription,
// deploymentSubscription,
// patientIdSubscription,
// createQuestionnaireLoadedSubscription,
// errorCreateQeustionnaireSubscription,
// ];
}

// This method must be present, even if empty.
ngOnDestroy() {
// We'll throw an error if it doesn't
}
}

Friday, 18 June 2021

What are the different types of binding available in Angular ?

Property Binding - binding is set in one direction from component's property to template. Property binding example.

<img [src]="ImageUrl">

Event Binding - It's used to bind any event. Event binding example.

<button (click)="onUpdate($event)">Save</button>

Two way binding - It's used for two-way binding. Two-way data binding example.

<input [(ngModel)]="name">

Attribute binding - It's used to set the value of attribute directly. Attribute binding example.

<button [attr.aria-label]="help">help</button>

Class binding - It's used to add or remove class names from class attribute. Class binding example.

 <span [class.specialClass]="isSpecialClass">Special class</span>

Style binding - It's used to add or remove the style from style attribute. Style binding example.

<button [style.color]="isSpecialClass ? 'blue' : 'black'">Click Me</button>


What is Angular DSL?

A domain-specific language (DSL) is a computer language specialized to a particular application domain. Angular has its own Domain Specific Language (DSL) which allows us to write Angular specific html-like syntax on top of normal html. It has its own compiler that compiles this syntax to html that the browser can understand. This DSL is defined in NgModules such as animations, forms, and routing and navigation.


Basically you will see 3 main syntax in Angular DSL.


(): Used for Output and DOM events.

[]: Used for Input and specific DOM element attributes.

*: Structural directives(*ngFor or *ngIf) will affect/change the DOM structure.

 

 

Tuesday, 26 November 2019

Angular Template Syntax and NgClass & NgStyle Directives

<!-- Native Class and Style Attributes -->
<input class="is-danger my-button" style="border: none; color: blue">
<!-- Angular class and style Bindings -->
<input [class.is-danger]="booleanProp" [style.border]="borderProp">
<!-- ngClass -->
<input [ngClass]="{'is-danger': booleanProp, 'myButton': true}">
<input [ngClass]="isDangerButton">
<!-- ngStyle -->
<input [ngStyle]="{'border': borderProp, 'color': colorProp}">
<input [ngStyle]="hasColorBorder">
<!--
booleanProp, borderProp, etc...
would be properties from our
Typescript class
-->

NgClass



NgClass can receive input via inline declarations, or a property/method from our TypeScript class. This can make the syntax feel more convoluted than it really is. Ultimately, NgClass can take the following as input:
  • A space-delimited String [ngClass]="is-info is-item has-border"
  • An Array of Strings [ngClass]="['is-info', 'is-item', 'has-border'"]
  • An Object [ngClass]="{'is-info': true, 'is-item': true}
All of the above examples are inline and could be replaced with a Typescript property/method as long as the expression returns valid input:
export class MyComponentClass {
myStringProperty = "is-info is-item has-border";
myArrayProperty = ['is-info', 'is-item', 'has-border'];
myObjectProperty = {'is-info': true, 'is-item': true};
}
  • [ngClass]="myStringProperty"
  • [ngClass]="myArrayProperty"
  • [ngClass]="myObjectProperty"


Key Points

  • We can pass a Typescript property/method or write an expression inline to our NgClass Directive
  • NgClass can take a String, Array of Strings, or Object Expression as input.
  • Under the hood, NgClass is adding/removing classes via Renderer2 addClass() and removeClass()
  • NgClass appends, it does not overwrite.



NgStyle

NgClass and NgStyle share a significant amount of functionality and behavior. The key difference is:
  • NgStyle takes a key-value pair object as input.
  • NgStyle applies styles and not classes.
  • NgStyle will overwrite styles defined by the native style attribute.

Syntax

NgStyle takes a key-value pair object, where the key is a CSS style. An optional suffix can be added to the key, making keys such as this viable:
[ngStyle]="{font-size.px: 16}" Instead of [ngStyle]="{font-size: 16px}"
Similar to NgClass, NgStyle can be passed input inline or use a Typescript property/method[ngStyle]="myObjectExpressionProperty"

Key Takeaways

  • NgStyle can accept a key-value pair as input, where the key is a valid CSS Style
  • NgStyle can be passed input via inline or a Typescript property or method
  • NgStyle under the hood utilizes Angular’s Renderer2 to invoke setStyle() and removeStyle()
  • NgStyle will overwrite existing styles on the element.