Angular Snippets

Putting constraints on selectors

angular

Component#selector and Directive#selector are just like CSS Selector. This means we can utilize some CSS pseudo-class to put constraints on our selector, making them more robust and provide better DX to our consumers

Suppose we have the following NgxLilGui component that wraps the lil-gui library.

To learn more about lil-gui, visit https://lil-gui.georgealways.com/

@Component({
  selector: "ngx-lil-gui",
  template: ` <ng-content></ng-content> `,
  standalone: true,
})
export class NgxLilGui implements OnInit, OnDestroy {
  @Input() config: Config;
  @Input() object: Record<string, any>;

  /* ... */
}

To make it flexible for the consumers, we allow the consumers to use config OR object to control the lil-gui library. In addition, the consumers can also use <ngx-lil-gui> without passing in anything. In this case, <ngx-lil-gui> acts as a group of other <ngx-lil-gui>

<ng-container #anchor />
<span #spanElement>This is a span</span>

<ngx-lil-gui>
  <!-- config object contains a dynamic HTMLElement that we can control -->
  <ngx-lil-gui [config]="config" />
  <ngx-lil-gui title="SPAN" [object]="spanElement.style" />
</ngx-lil-gui>

However, there’s nothing to stop the consumers to use both [config] and [object] on <ngx-lil-gui>

<ngx-lil-gui [config]="config" [object]="object" />

To apply this constraint, we can modify our selector as follow:

@Component({
  selector: `
    ngx-lil-gui:not([config]):not([object]),
    ngx-lil-gui[config]:not([object]),
    ngx-lil-gui[object]:not([config])
  `,
  /* ... */
})
export class NgxLilGui implements OnInit, OnDestroy {
  /* ... */
}

Now, the consumers can instantiate NgxLilGui component by using <ngx-lil-gui />, <ngx-lil-gui [config] />, or <ngx-lil-gui [object] /> but never <ngx-lil-gui [config] [object] />

Back to snippets