DEV Community

wszgrcy
wszgrcy

Posted on

UnOfficial Implementation of Angular's Selectorless Components

  • As is well known, when defining components in Angular, a custom tag must be generated. In some cases, this can be inconvenient when using CSS layout.
  • Although the official team has begun to consider implementing selectorless components, it is still in the planning stage, and it's uncertain how long it will take to be realized.

Principle

  • As is well known, structural directives can dynamically insert templates.
  • Template content can be customized and can also use all properties and methods within the component.
  • Therefore, it's sufficient to turn the component into a template to achieve this.
  • The method is also simple, just wrap a ng-template around the component's html
  • Now that we have the template, we only need to consider how to use it.
  • This is also simple: dynamically create a component, which returns the component instance. Through the instance, we can get the template reference.
  • Since we have the template reference, we can use viewContainerRef to insert it.
  • As the inserted content is a template, the component is only created but not actually inserted into the DOM with a selector.
  • This achieves the selectorless component.

Implementation

  • The following code is only for demonstrating the principle. For more detailed information, please refer to the repository
  • Directive
// Create component reference, existing only in memory
this._componentRef = createComponent(this.selectlessOutlet(), {});
// Get the instantiated component, note that the component needs a templateRef to save the template reference
const instance = this._componentRef.instance as {
  templateRef: Signal<TemplateRef<any>>;
};
// Insert the template in a structural directive (similar to ngIf ngFor)
this.#viewContainerRef.createEmbeddedView(instance.templateRef());
// Bind lifecycle
this.#appRef.attachView(this._componentRef.hostView);
this._componentRef.changeDetectorRef.detectChanges();
Enter fullscreen mode Exit fullscreen mode
  • Selectorless component part
<ng-template #templateRef> 123 </ng-template>
Enter fullscreen mode Exit fullscreen mode
@Component({})
export class InsertComponent implements OnInit {
  public templateRef = viewChild.required('templateRef');
}
Enter fullscreen mode Exit fullscreen mode
  • Usage part
<ng-container *selectlessOutlet="InsertComponent;inputs:{}"> </ng-container>
Enter fullscreen mode Exit fullscreen mode

Limitations

  • Of course, this method has some limitations.
  • The implementation of ng-content will be very complex; it needs to use ng-template references to replace input variables.
  • Some directives may be restricted, because components implemented in this way are essentially a shell and cannot access the real element. > Because at this point, the ElementRef gets an element that is not in the DOM.

Faster Usage?

  • Piying View has already supported custom selectorless component definitions and can switch them conveniently. > Piying can be considered as the Pro plus version of ngx-formly, with similar concepts to ngx-formly, but with clearer logic, safer, supports strong typing, multi-framework, and more features.

Final Words

Top comments (0)