Home > Software design >  How to use a directive to pass default values in angular
How to use a directive to pass default values in angular

Time:07-28

I have created a custom component that has many input properties. However, one thing I have noticed when using this component is that many of the input properties are the same within the parent component.

An example usage looks like this:

<yes-no
 controlName="isAwesome"
 labelKeyBase="MODULE.PAGE_X"
 validationKeyBase="VALIDATION.CUSTOM_X"
 someOtherProp="true"
></yes-no>

I have been using a library called transloco and noticed some functionality that would be very useful in this situation. Unfortunately, I have no idea how it would be implemented.

https://ngneat.github.io/transloco/docs/translation-in-the-template#utilizing-the-read-input

I'm wondering if there is a simplified example out there that demonstrates how to pass a value from a parent directive to a child component. Basically, my goal is to turn the above code into something like this:

<ng-container *yesNoConfig="labelKeyBase: 'MODULE.PAGE_X'; validationKeyBase: 'VALIDATION.CUSTOM_X'">
 <yes-no controlName="isAwesome"></yes-no>
 <yes-no controlName="isClean"></yes-no>
 <yes-no controlName="isShort"></yes-no>
</ng-container>

CodePudding user response:

That looks like a custom *ngFor, and the t is likely a higher order function passed to the de-sugared ng-template as the $implicit value in the context

There's a good example to follow and get started with here:

The code for that transloco directive is also on GitHub

CodePudding user response:

Here's a directive that applies arbitrary attributes to all immediate children of the container:

@Directive({
  selector: '[setAttributes]',
})
export class SetAttributesDirective {
  @Input('setAttributes') atts: { [key: string]: string } = {};

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef
  ) {}

  ngOnInit() {
    const keys = Object.keys(this.atts);
    const viewRef = this.viewContainer.createEmbeddedView(this.templateRef);
    for (const node of viewRef.rootNodes) {
      if (typeof node.setAttribute !== 'function') continue;
      const el = node as HTMLElement;
      for (const key of keys) el.setAttribute(key, this.atts[key]);
    }
  }
}

Not very typesafe since viewRef.rootNodes is type any[] but what can you do... I put somewhat of a typeguard anyway. The first entry is actually the ng-container itself, and nested templates / ng-containers will also not have a setAttribute function, throwing an error without the typeguard. Could definitely be improved, but at least you get the gist.

You'd use it like this:

<ng-container *setAttributes="{ type: 'number', value: '5', min: '0', max: '10' }">
  <input />
  <input />
  <input />
  <input />
</ng-container>

Associated docs: https://angular.io/guide/structural-directives

Stackblitz example: https://stackblitz.com/edit/angular-ivy-1eyjlo?file=src/app/app.component.html


Your specific example

<ng-container *setAttributes="{ labelKeyBase: 'MODULE.PAGE_X', validationKeyBase: 'VALIDATION.CUSTOM_X' }">
 <yes-no controlName="isAwesome"></yes-no>
 <yes-no controlName="isClean"></yes-no>
 <yes-no controlName="isShort"></yes-no>
</ng-container>
  • Related