Skip to content

Fiori Next Style Guide

Platon Rov edited this page Feb 16, 2022 · 6 revisions

In general we follow Angular styleguide, but there are specific recommendations from our side too. If you can not find rules for your topic of interest on this page, you can refer to Angular styleguide for help.

Approach to development

Class inheritance and common behaviors

Avoid inheritance of classes. Especially marking parent properties with angular's decorators(@Input, @Output, @HostListener, @HostBinding...). If there is some functionality, that is needed in more than one component and can be described as "common behavior", extract it into the separate directive. In general approach development with "composition over inheritance". If you need data from that extracted directive, you can inject that directive into the main component using Lightweight injection tokens.

References to classes

Avoid referencing to concrete classes from components/directives if those classes are not tightly related to each other and user will always use both of them together. Use Injection tokens instead of directly referencing classes. This will make testing easier, as well as will make code more atomic. Depend on interfaces and abstractions instead of implementation.

Native elements

Use as much native elements in your development as you can. Browsers are smart, very smart. They have their own way of dealing with most native elements. So instead of replacing them(native tags, elements) and trying to fill the void of incomplete functionality, enhance existing with added features. Yes, we can not always reuse native tags and that is ok, but do not try to replace button with my-button-component, because side effects sometimes are not visible from the first glance.

Setter/Getter vs. ngOnChanges

If you have to react on one or two input changes, go ahead and use @Input with property setter and getter, but if you rely on more than that, you should probably consider moving that logic to ngOnChanges.

Generic components, directives, services, functions and etc.

For example if you have select component, which has to receive list of items. Consider writing class with generic type. If class is called MySelectComponent, write MySelectComponent<ValueType>. Then in @Input and @Output properties you can use that type as needed. That will help a lot to the end users with autogenerations and generally ensure more type-safed environment.

Data source vs ng-content

Strictly decide before the implementation whether component should use ng-content (probably with select) for its children or use data source approach (when array/etc of items passed as @Input). There won't be a chance to change it after. Go with data source if sorting, filtering or searching should be provided for the children, otherwise go with ng-content approach.

Components

HTML and CSS files

If your component HTML contains up to 3 lines of code, feel free to include into the template metadata, otherwise, please create separate HTML file for component.

If your component CSS contains up to 15 lines of code, feel free to include into the styles metadata, otherwise, please create separate CSS file for component.

We use SASS for styling our components, so always use scss extension styles when writing component CSS files.

Avoid at all costs writing custom CSS in component styles, those rules should be extracted to the fundamental-styles repository. Create PR there and continue working on features for ngx.

Selectors

All of the components should have prefix fn. Component selectors always should be in dash-case. Even if selector is attribute selector(e.g. li[fn-list-item]). If component may have custom selector and attribute selector, then you can freely separate them using ,, but in such cases, respect dash-case rule. So in given example component selector would be fn-list-item, li[fn-list-item]. Pay attention that custom selector is moved to the attribute. Read about how to decide whether should be used element or attribute selector: https://angular.io/guide/accessibility#augmenting-native-elements

Inputs and Outputs metadata

In general we avoid using inputs metadata, but in case your component class extends other base class, which has inputs and outputs described, it is better to list those inputs and outputs to the child component class metadata, because that way it becomes easier to find out what inputs and outputs component has without looking into the parent classes.

Host metadata

If your component has many @HostBindings, then move them to host metadata, so that they are accessible and visible from one place.

Change detection

Prefer change detection OnPush over Default. Prefer markForCheck() if your logic does not require immediate feedback.

Content Projection

Go with the ng-content if the slot you're passing definitely won't need any context and parent component doesn't need to know if that slot is passed, otherwise use structural directives approach. There may be a cases when the slot should be wrapped in some html in the parent's template and if the slot won't be passed there will be an empty divs.

CSS Classes applying - TBD

Directives

Selector

Always use camelCase and prefix them with fn. If you have some atomic directive, let's say fnHoverable, then allow user to disable that feature by passing [fnHoverable]="false" property. This can be achieved by adding @Input() fnHoverable: boolean to your directive and then adding appropriate logic for turning on and off the feature.

Inputs and outputs - TBD

Structural directives

Use structural directives to get the template of child items to render it inside the parent component when the context matters (i.e. variables used in the template) or you need ensure if the template is provided. Here is the reference how to do it. Don't forget to rely on the Lightweight Injection Tokens instead of direct references.

Unit Tests - TBD

Clone this wiki locally