Skip to content

Support UI properties on Angular Components #1547

Open
@tiagoblackcode

Description

@tiagoblackcode

Is your feature request related to a problem? Please describe.
Currently angular components cannot be styled through XML attributes nor do they have a representation in the UI tree (e.g. <my-component backgroundColor="red" paddingTop="10">). To overcome this and other limitations, Angular components are frequently wrapped either outside or inside in some kind view container (StackLayout is perhaps the most common).

Describe the solution you'd like
A custom component annotation (either as a replacement or complementary to Angular's @Component) i.e. @NativeScriptComponent which allows the developer to provide a viewClass property to specify which Nativescript view to use for a given component.

Describe alternatives you've considered
Alternatively to the component annotation, one can use registerElement('my-component-selector', () => StackLayout) to manually associate the Angular component with a UI view.

Additional context
PoC for the custom component annotation and use-case:

function NativeScriptComponent(meta: Component & { viewClass: ViewClass }) {
  const viewClass = meta.viewClass;
  delete meta.viewClass;

  const componentMeta = meta as Component;
  const ngComponentDecorator = Component(componentMeta);

  return function<T extends { new(...args:any[]): {} }>(constructor: T) {
    ngComponentDecorator(constructor);
    
    if (!isKnownView(componentMeta.selector)) {
      registerElement(componentMeta.selector, () => viewClass);
    } else {
      console.warn(`Component with selector ${componentMeta.selector} is already registered`);
    }
  }
}

Component declaration:

@NativeScriptComponent({
  moduleId: module.id,
  viewClass: StackLayout,
  selector: 'nativescript-component',
  template: '<Label text="Hello, World"></Label>',
  host: {
    'class': 'm-10 p-10'
  },
})
export class TestComponent implements OnInit {
  constructor(private elementRef: ElementRef) {
    // elementRef.nativeElement is a StackLayout
  }
}

Usage:

<!-- app.component.html -->
<nativescript-component backgroundColor="red"></nativescript-component>

Additional Notes

  • This way of overriding the @Component annotation might not be supported across all versions of Angular. This was tested with Angular 6.
  • Host properties @Component({ host: { 'borderColor': 'red' }, ... }) do not seem to work. It does.
  • registerElement is global while the component is scoped to the module where it is declared and, when exported, the modules that import the declaring module. This means that two components with the same name declared on different modules would clash in the registerElement phase.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions