Fiori Next Style Guide - SAP/fundamental-ngx GitHub Wiki
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.
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.
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.
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.
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.
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.
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.
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.
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
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.
If your component has many @HostBinding
s, then move them to host
metadata, so that they are accessible and visible from one place.
Prefer change detection OnPush over Default. Prefer markForCheck()
if your logic does not require immediate feedback.
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.
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.
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.