Skip to content

Writing a component

Copy of sumaris-app/.agents/rules/component.md (rule written for AI coding agents, when creating new UI component). Do not edit here: run npm run site:sync-rules to update it.

  • For each Angular component:

    • Use a separate file for the HTML template;
    • Use the Ionic framework, and (if necessary) Angular Material;
    • Ionic is used with its standalone build (provideIonicAngular()), never the lazy IonicModule:
      • Import Ionic components through AppIonicModule (@app/shared/ionic.module) - already exported by AppSharedModule;
      • Any new <ion-*> tag MUST be added to APP_IONIC_COMPONENTS (src/app/shared/ionic.module.ts), otherwise the element stays inert (not detected at compile time);
      • Import controllers and types (ModalController, AlertController, IonContent...) from @ionic/angular/standalone, never from @ionic/angular;
      • An <ion-icon> with a static name must be registered in APP_ICONS (src/app/app.icons.ts);
    • Use the Moment class for dates;
    • Use RxState with providers: [RxState] in the @Component declaration;
    • Right above each component class, declare an interface MyComponentState:
      • Replace "MyComponent" with the name of the component;
      • Add the component's dynamic attributes to this interface;
    • Within the constructor:
      • Limit the parameters facilitate inheritance: by using inject() function (on each attribute declaration) or by using the injector: Injector in the constructor;
      • Define all parameters with protected visibility;
      • Add a parameter state: RxState<MyComponentState>.
    • For each dynamic attribute of the component:
      • Define the attribute with its basic type in the MyComponentState class;
      • In the component, define a getter and a setter with `@Input; that uses state:
        • Use the decorator @RxStateProperty() attribute: anyType - will generate a state's property getter/setter :
          get attribute(): anyType {
            return this.state.get('attribute');
          }
          @Input() set attribute(value: anyType) {
            this.state.set('attribute', () => value);
          }
          
        • Is to observed a state's property, use the decorator @RxStateSelect() attribute$: Observable<anyType> - that is similar to:
          attribute$ = this.state.select('attribute');
          
    • For modals (if needed):
      • Use IonicModal.
      • Do not define the modal in the HTML template (inline) but in a separate component.
      • Manage the modal from the calling component via ModalController.
    • For any generated code (by GPT or otherwise):

      • Add a comment line at the beginning of the class indicating that the code is under a free license (GPL version 3), but do not write out the full license.
    • Use the ngx-translate library for labels:

      • Import the standalone TranslatePipe from @ngx-translate/core (in the component's own imports array, or the declaring NgModule's imports) — TranslateModule / TranslateModule.forChild() is no longer used in this codebase.
      • Add an i18n key prefix "MY_COMPONENT." before each i18n key.
      • In the template, translate each label by indicating the i18n key followed by the translate pipe.
      • Define the translation for each key in a en.json translation file.