TypeScript and Angular Conventions
These conventions apply to the Angular client under src/main/webapp. They follow current Angular practice:
standalone components, signals, and the built-in template control flow.
Components and routes
- Use standalone Angular components.
- Use lazy loading for route-level features so that the initial bundle stays small.
- Use
ChangeDetectionStrategy.OnPush. - Keep route paths explicit: every variable segment is preceded by a unique textual segment.
Naming and formatting
- Use kebab-case file names.
- Use PascalCase for classes, types, and enums. Do not prefix interfaces with
I. - Use camelCase for functions, properties, and local variables.
- Use SCREAMING_SNAKE_CASE for constants.
- Do not prefix private members with
_. - Use descriptive whole words instead of terse abbreviations.
- Use 4-space indentation and single quotes.
- Use arrow functions instead of anonymous function expressions, and always wrap arrow parameters in parentheses.
- Always use curly braces for loop and conditional bodies, except for same-line statements.
Signals and dependency injection
Signals make change detection predictable with OnPush, so new code uses the signal-based APIs:
input()andinput.required()instead of@Input()output()instead of@Output()viewChild()andviewChild.required()instead of@ViewChild()viewChildren()instead of@ViewChildren()signal(),computed(), andeffect()for component state
Do not add legacy decorators such as @Input, @Output, @ViewChild, @ViewChildren, @ContentChild, or
@ContentChildren in new code. Prefer inject() over constructor injection.
Templates
- Use the built-in control flow
@if,@for, and@switch. Do not add new*ngIf,*ngFor, or*ngSwitch. - Do not call component methods or getters from templates; signals are the exception. Precompute values with
computed()or assign view-ready state before rendering.
For example, the Explorer derives the number of selectable features once instead of counting in the template:
readonly featureCount = computed(() => this.response()?.features.filter((feature) => feature.selectable).length ?? 0);
Types
- Never use
any; keep client code strictly typed. - Avoid
nullwhereundefinedworks. - Prefer interfaces over type aliases whenever an interface can express the shape.
- Do not use anonymous object shapes for meaningful data. Define named interfaces.
- Put local type definitions near the top of the file.
- Do not export types, constants, or helpers unless another file needs them.
- Do not introduce global types or global values.
- Treat objects and arrays as immutable outside the component or helper that created them.
Services and API calls
- Keep API calls in the feature-model API services, not in route components.
- Keep validation display components separate from the validation service logic.
Client Foundations describes the API services.
Accessibility basics
- Use buttons for actions and links for navigation.
- Associate labels with form controls using
forandid, or by wrapping the input in the label.
Component libraries
The client uses Bootstrap-compatible SCSS. Use Bootstrap utilities sparingly, and do not add ng-bootstrap,
FontAwesome, PrimeNG, or another component library.