@finlexlabs/stepper
v0.0.2
Published
Library Name: finlex-stepper Package Name: @finlexlabs/stepper Repo Name: fx-ng-components
Downloads
3
Readme
Finlex Stepper (@finlexlabs/stepper)
Library Name: finlex-stepper Package Name: @finlexlabs/stepper Repo Name: fx-ng-components
Steps to Build & Publish Library
Package Renaming
Go to ./src/finlex-stepper/package.json
Rename package name from finlex-stepper
to @finlexlabs/stepper
Build
npm run build:stepper
It will build finlex-stepper using ng-packagr.
The build artifacts will be stored in the dist/
directory.
Publishing
After building your library with ng build:stepper
, go to the dist folder cd dist/finlex-stepper
and run npm publish
.
NOTE: Finlex Stepper is a modified version of Material Stepper Angular (@angular/stepper module) that is built on top of Angular Stepper CDK so in case you're not familiar with them already, following recoures will be a good start before you understand finlex-form-control and its functionality:
Background knowledge:
- Read here an intro to Angular's Material Stepper.
- Read here an intro to Angular's Stepper CDK.
- Read here for an intro into
FinlexFormGroup
, we use them in stepper to determine and revert if a stepControl has any changes.
Mostly all the behaviour of MatStepper is still possible. All the customizations from that behaviour are mentioned below.
(TL;DR) Simple example to use finlex-stepper with form:
module.ts
import { FinlexStepperModule } from '@finlex/components/finlex-stepper';
@NgModule({
imports: [
FinlexStepperModule
]
})
export class ProductsModule { }
controller.ts
// It is not necessary to have a form for stepper
constructor(
){}
// this will set this.stepper value
@ViewChild('stepper', { static: false }) stepper;
const stepCreateProduct: FormGroup = new FinlexFormGroup({
name: new FinlexFormControl({
placeholder: 'placeholder text',
value: this.product.name
})
})
// It's only required to use function with stepper.next() if we want to make an async call before allowing to change the step.
onActionBeforeNextStep(){
// do some async action
this.productService.save(this.stepCreateProduct)
.subscribe(() => {
this.stepCreateProduct.commitValue();
this.stepper.next(); // this will change the step
})
}
view.ts
<finlex-stepper #stepper>
<finlex-step [stepControl]="stepCreateProduct"
[stepControlValue]="product">
<ng-template matStepLabel>{{'STEP_WITH_ASYCN_CALL'}}</ng-template>
<finlex-form-control fxFlex="40"
[control]="stepCreateProduct.get('name')">
</finlex-form-control>
<button mat-button
[disabled]="stepCreateProduct.invalid"
(click)="onActionBeforeNextStep()">
{{'NEXT_LABEL' | translate}}
</button>
</finlex-step>
<finlex-step>
<ng-template matStepLabel>{{'STEP_WITHOUT_FORM'}}</ng-template>
<button mat-button
matStepperPrevious>
{{'NEXT_LABEL' | translate}}
</button>
</finlex-step>
</finlex-stepper>
FinlexStepperModule declarations
There are no changes to the following directives and they behave so far as it is:
MatStepperNext
,MatStepperPrevious
,MatStepLabel
. Feel free to use Angular API Doc links to understand them.The stepper component called
finlex-stepper
is inspired bymat-vertical-stepper
(which also inheritsmat-stepper
).The step component called
finlex-step
inspired bymat-step
.- The FinlexStep has a new @Input() binding called
disable
. If a step has disable true, the header icon of the step is rendered with a special design (low opacity) and its not possible to click on the step header to open the step.
- The FinlexStep has a new @Input() binding called
The step header called
finlex-step-header
is inspired bymat-step-header
but this component is not so relavent since its only used for internal renderring of stepper and has no affect in usage.
Customizations
The support for
matStepperIcon
template has been removed since our UI toolkit doesn't require this feature. Instead, we always show step number as the default icon for every step (in any step state).FinlexStepper uses *ngIf directive to prevent the stepper from rendering all steps at once (and hiding them in DOM), which was the default behavior. Instead, the *ngIf ensures that only active step is rendered in DOM and therefore, when we change the step, the lifecycle of other step components is only triggered when that step is active.
If a
finlex-step
has[disable]
binding as true, the step header icon will be styled differently and it will not be possible to transition to this step.FinlexStepper does not use the
[linear]
binding of Material Stepper, instead it performs its own logic for similar behaviour by overriding the(click)
binding of step header (when user clicks on other steps titles). This click function performs several checks before transition to another step:If the steps prior to the clicked step have
stepControl
, it checks that all the previousstepControl
's are in valid state. Otherwise, the transition to the step is denied (nothing happens when clicking on the header). E.G. User is on Step 2 and Step 3 is invalid, so user cannot click on Step 4 directly.If the current step has
stepControl
that is dirty, it checks whether the current step is valid before doing the transition. If not, it shows a dialog to warn the user that their changes will be reset if they continue to change the step directly (without saving). If user continues, thestepControl
changes are *reset before performing the transition.If the current step has
stepControl
that is dirty, it checks whether the step has any *changes. If yes, it shows a dialog to warn the user that their changes will be reset if they continue to change the step directly (without saving). If user continues, thestepControl
changes are *reset before performing the transition.
To perofrm actions like "reset" and check if a
stepControl
has "changes", thestepControl
should be of typeFinlexFormGroup
. To learn more about how FinlexFormGroup provides support for this, please readhere
.
Future Enhancement (suggestive):
- Remove the
stepControlValue
binding ofFinlexStep
and encapsulate the logic to check for changes of a form toFinlexFormGroup
: https://finlex.atlassian.net/browse/PX-1139