Sahil Jalan
Sahil Jalan

Reputation: 121

How to decode existing structural directive string syntax in our custom directive in angular

Like I said, I want to use the existing structural directive string based syntax in custom directive

<element *ngFor='let x of array;let last = last;'></element>

I don't find any detailed docs, how we can decode the above syntax in our custom structural directive. I know we can use this syntax with all structural directive *xyz but I always use [xyz] instead. I try to find angular official docs but got nothing.

So I move into their code to understand *NgFor in github, and I got it all except how they are decoding the syntax.

If you see the selector it is like below

@Directive({selector: '[ngFor][ngForOf]'})

@Input()
set ngForTrackBy(fn: TrackByFunction<T>) {
    //definition
}

And all inputs method starts with selector prefix like ngForTrackBy. is it like this only? do we have to follow the selector prefix?
If Yes then what are all other things we can do with this prefix based approach? If no then what is the right approach?

Upvotes: 1

Views: 248

Answers (1)

Max Koretskyi
Max Koretskyi

Reputation: 105547

It's the job of the compiler to match the variables defined with the let syntax and the context passed into the embedded view. You can define as many variables as you want, but if you don't pass the values for them through the context, their values will be undefined.

Here I'm using a custom my directive and defining two variables a and b with the let syntax:

<ng-template my let-a=a let-b=b let-c=c>
  <span>inside my, a is {{a}}, b is {{b}}, c is undefined: {{c === undefined}}</span>
</ng-template>

Then when describing the directive I pass the context with variable values to the embedded view:

import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[my]'
})
export class MyDirective {
  constructor(public vc: ViewContainerRef, public t: TemplateRef<any>) {
  }

  ngOnInit() {
    const t = this.vc.createEmbeddedView(this.t, {a: 3, b: 4});
  }
}

The same holds true for the ngForOf directive, here's how the context looks for it:

export class NgForOfContext<T, U extends NgIterable<T> = NgIterable<T>> {
  constructor(public $implicit: T, public ngForOf: U, public index: number, public count: number) {}

  get first(): boolean {
    return this.index === 0;
  }

  get last(): boolean {
    return this.index === this.count - 1;
  }

  get even(): boolean {
    return this.index % 2 === 0;
  }

  get odd(): boolean {
    return !this.even;
  }
}

You can also use a shorthand syntax with custom directive:

<span *my="let a=a; let b=b; let c=c;">inside my, a is {{a}}, b is {{b}}, c is undefined: {{c === undefined}}</span>

Upvotes: 5

Related Questions