Skip to content

Commit 38d39d7

Browse files
authored
Allow promises in canExit and canEnter inputs (#45)
- introduce Promise<boolean> as the result for canGoToStep - extend tests to contain tests for Promise<boolean> - modify the README to reflect the done changes to canExit and canEnter - refactor some tests - improve some method documentation
1 parent 0c9bd9a commit 38d39d7

17 files changed

+673
-350
lines changed

README.md

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -164,18 +164,17 @@ you need to set the `navigationSymbol` input attribute of the step to `&#xf2dd;`
164164
Sometimes it's required to only allow the user to enter a specific step if a certain validation method returns true.
165165
In such a case you can use the `[canEnter]` input of the targeted wizard step.
166166
This input can be either a boolean, which directly tells the wizard if the targeted step can be entered,
167-
or a lambda function, taking a `MovingDirection` and returning a boolean.
167+
or a lambda function, taking a `MovingDirection` and returning a `boolean` or a `Promise<boolean>`.
168168
This function will then be called, with the direction in which the targeted step will be entered, whenever an operation has been performed, that leads to a change of the current step.
169169
It then returns true, when the step change should succeed and false otherwise.
170170

171171
#### \[canExit\]
172172
If you have an additional check or validation you need to perform to decide, if the step can be exited (both to the next step and to the previous step),
173-
you can either pass a boolean or a function, taking a `MovingDirection` enum and returning a boolean, to the `[canExit]` attribute of the wizard step.
174-
This boolean or function is taken in account when an operation has been performed, that leads to a change of the current step.
173+
you can either pass a boolean or a function, taking a `MovingDirection` enum and returning a boolean or a `Promise<boolean>`, to the `[canExit]` attribute of the wizard step.
174+
This boolean, or function, is taken into account, when an operation has been performed, which leads to a transition of the current step.
175175
If `[canExit]` has been bound to a boolean, it needs to be true to leave the step either in both a forwards and backwards direction.
176-
If only exiting one direction should be covered, you can pass a function taking `MovingDirection` and returning a boolean to `[canExit]`.
177-
This function will then be called, with the direction in which the current step should be moved, whenever an operation has been performed, that leads to a change of the current step.
178-
It then returns true, when the step change should succeed and false otherwise.
176+
If only exiting in one direction should be covered, you can pass a function, taking a `MovingDirection` and returning a boolean, to `[canExit]`.
177+
This function will then be called whenever an operation has been performed, that leads to a change of the current step.
179178

180179
#### \(stepEnter\)
181180
If you need to call a function to do some initialisation work before entering a wizard step you can add a `stepEnter` attribute to the wizard step environment like this:
@@ -199,15 +198,15 @@ either by pressing on a component with a `nextStep` or `previousStep` directive,
199198
#### Parameter overview
200199
Possible `<wizard-step>` parameters:
201200

202-
| Parameter name | Possible Values | Default Value |
203-
| ----------------------------- | ------------------------------------------------- | ------------- |
204-
| [stepTitle] | string | null |
205-
| [navigationSymbol] | string | '' |
206-
| [navigationSymbolFontFamily] | string | null |
207-
| [canEnter] | function(MovingDirection): boolean &#124; boolean | true |
208-
| [canExit] | function(MovingDirection): boolean &#124; boolean | true |
209-
| (stepEnter) | function(MovingDirection) | null |
210-
| (stepExit) | function(MovingDirection) | null |
201+
| Parameter name | Possible Values | Default Value |
202+
| ----------------------------- | ---------------------------------------------------------------------------------------------------- | ------------- |
203+
| [stepTitle] | string | null |
204+
| [navigationSymbol] | string | '' |
205+
| [navigationSymbolFontFamily] | string | null |
206+
| [canEnter] | function(MovingDirection): boolean &#124; function(MovingDirection): Promise<boolean> &#124; boolean | true |
207+
| [canExit] | function(MovingDirection): boolean &#124; boolean | true |
208+
| (stepEnter) | function(MovingDirection) | null |
209+
| (stepExit) | function(MovingDirection) | null |
211210

212211
### \<wizard-completion-step\>
213212
In addition to the "normal" step component `<wizard-step>` it's also possible to define an optional `<wizard-completion-step>`.
@@ -223,13 +222,13 @@ because it can't be exited.
223222
#### Parameter overview
224223
Possible `<wizard-completion-step>` parameters:
225224

226-
| Parameter name | Possible Values | Default Value |
227-
| ----------------------------- | ------------------------------------------------- | ------------- |
228-
| [stepTitle] | string | null |
229-
| [navigationSymbol] | string | '' |
230-
| [navigationSymbolFontFamily] | string | null |
231-
| [canEnter] | function(MovingDirection): boolean &#124; boolean | true |
232-
| (stepEnter) | function(MovingDirection) | null |
225+
| Parameter name | Possible Values | Default Value |
226+
| ----------------------------- | ---------------------------------------------------------------------------------------------------- | ------------- |
227+
| [stepTitle] | string | null |
228+
| [navigationSymbol] | string | '' |
229+
| [navigationSymbolFontFamily] | string | null |
230+
| [canEnter] | function(MovingDirection): boolean &#124; function(MovingDirection): Promise<boolean> &#124; boolean | true |
231+
| (stepEnter) | function(MovingDirection) | null |
233232

234233
### \[enableBackLinks\]
235234
In some cases it may be required that the user is able to leave an entered `wizard-completion-step`.
@@ -393,15 +392,15 @@ This can be done by defining adding the `[wizardStep]` directive to the componen
393392
#### Parameter overview
394393
Possible `[wizardStep]` parameters:
395394

396-
| Parameter name | Possible Values | Default Value |
397-
| ----------------------------- | ------------------------------------------------- | ------------- |
398-
| [stepTitle] | string | null |
399-
| [navigationSymbol] | string | '' |
400-
| [navigationSymbolFontFamily] | string | null |
401-
| [canEnter] | function(MovingDirection): boolean &#124; boolean | true |
402-
| [canExit] | function(MovingDirection): boolean &#124; boolean | true |
403-
| (stepEnter) | function(MovingDirection) | null |
404-
| (stepExit) | function(MovingDirection) | null |
395+
| Parameter name | Possible Values | Default Value |
396+
| ----------------------------- | ---------------------------------------------------------------------------------------------------- | ------------- |
397+
| [stepTitle] | string | null |
398+
| [navigationSymbol] | string | '' |
399+
| [navigationSymbolFontFamily] | string | null |
400+
| [canEnter] | function(MovingDirection): boolean &#124; function(MovingDirection): Promise<boolean> &#124; boolean | true |
401+
| [canExit] | function(MovingDirection): boolean &#124; boolean | true |
402+
| (stepEnter) | function(MovingDirection) | null |
403+
| (stepExit) | function(MovingDirection) | null |
405404

406405
### \[wizardCompletionStep\]
407406
In addition to the possibility of defining a normal wizard step in a custom component,
@@ -422,13 +421,13 @@ that contains the wizard completion step.
422421
#### Parameter overview
423422
Possible `[wizardCompletionStep]` parameters:
424423

425-
| Parameter name | Possible Values | Default Value |
426-
| ----------------------------- | ------------------------------------------------- | ------------- |
427-
| [stepTitle] | string | null |
428-
| [navigationSymbol] | string | '' |
429-
| [navigationSymbolFontFamily] | string | null |
430-
| [canEnter] | function(MovingDirection): boolean &#124; boolean | true |
431-
| (stepEnter) | function(MovingDirection) | null |
424+
| Parameter name | Possible Values | Default Value |
425+
| ----------------------------- | ---------------------------------------------------------------------------------------------------- | ------------- |
426+
| [stepTitle] | string | null |
427+
| [navigationSymbol] | string | '' |
428+
| [navigationSymbolFontFamily] | string | null |
429+
| [canEnter] | function(MovingDirection): boolean &#124; function(MovingDirection): Promise<boolean> &#124; boolean | true |
430+
| (stepEnter) | function(MovingDirection) | null |
432431

433432
### Accessing the wizard component instance
434433
Sometimes it's required to access the wizard component directly.

src/components/wizard-navigation-bar.component.spec.ts

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
1+
import {async, ComponentFixture, fakeAsync, TestBed, tick} from '@angular/core/testing';
22
import {Component, ViewChild} from '@angular/core';
33
import {WizardNavigationBarComponent} from './wizard-navigation-bar.component';
44
import {WizardComponent} from './wizard.component';
@@ -88,11 +88,12 @@ describe('WizardNavigationBarComponent', () => {
8888
expect(navigableLi.length).toBe(0);
8989
});
9090

91-
it('should show the second step correctly', () => {
91+
it('should show the second step correctly', fakeAsync(() => {
9292
const navBar = wizardTestFixture.debugElement.query(By.css('wizard-navigation-bar'));
9393

9494
// go to second step
9595
navigationMode.goToNextStep();
96+
tick();
9697
wizardTestFixture.detectChanges();
9798

9899
const allLi = navBar.queryAll(By.css('li'));
@@ -124,15 +125,19 @@ describe('WizardNavigationBarComponent', () => {
124125

125126
expect(navigableLi.length).toBe(1);
126127
expect(navigableLi[0]).toBe(allLi[0]);
127-
});
128+
}));
128129

129-
it('should show the third step correctly', () => {
130+
it('should show the third step correctly', fakeAsync(() => {
130131
const navBar = wizardTestFixture.debugElement.query(By.css('wizard-navigation-bar'));
131132

132133
// go to second step
133134
navigationMode.goToNextStep();
135+
tick();
136+
wizardTestFixture.detectChanges();
137+
134138
// go to third step
135139
navigationMode.goToNextStep();
140+
tick();
136141
wizardTestFixture.detectChanges();
137142

138143
const allLi = navBar.queryAll(By.css('li'));
@@ -165,13 +170,14 @@ describe('WizardNavigationBarComponent', () => {
165170
expect(doneLi.length).toBe(2);
166171
expect(navigableLi[0]).toBe(allLi[0]);
167172
expect(navigableLi[1]).toBe(allLi[1]);
168-
});
173+
}));
169174

170-
it('should show the third step correctly, after jump from first to third step', () => {
175+
it('should show the third step correctly, after jump from first to third step', fakeAsync(() => {
171176
const navBar = wizardTestFixture.debugElement.query(By.css('wizard-navigation-bar'));
172177

173178
// go to third step and jump over the optional second step
174179
navigationMode.goToStep(2);
180+
tick();
175181
wizardTestFixture.detectChanges();
176182

177183
const allLi = navBar.queryAll(By.css('li'));
@@ -204,15 +210,19 @@ describe('WizardNavigationBarComponent', () => {
204210
expect(navigableLi.length).toBe(2);
205211
expect(navigableLi[0]).toBe(allLi[0]);
206212
expect(navigableLi[1]).toBe(allLi[1]);
207-
});
213+
}));
208214

209-
it('should show the first step correctly, after going back from the second step to the first step', () => {
215+
it('should show the first step correctly, after going back from the second step to the first step', fakeAsync(() => {
210216
const navBar = wizardTestFixture.debugElement.query(By.css('wizard-navigation-bar'));
211217

212218
// go to second step
213219
navigationMode.goToNextStep();
220+
tick();
221+
wizardTestFixture.detectChanges();
222+
214223
// go back to first step
215224
navigationMode.goToPreviousStep();
225+
tick();
216226
wizardTestFixture.detectChanges();
217227

218228
const allLi = navBar.queryAll(By.css('li'));
@@ -243,16 +253,20 @@ describe('WizardNavigationBarComponent', () => {
243253
expect(defaultLi[0]).toBe(allLi[2]);
244254

245255
expect(navigableLi.length).toBe(0);
246-
});
256+
}));
247257

248258
it('should show the first step correctly, after first jumping from the first to the third step ' +
249-
'and then back from the third step to the first step', () => {
259+
'and then back from the third step to the first step', fakeAsync(() => {
250260
const navBar = wizardTestFixture.debugElement.query(By.css('wizard-navigation-bar'));
251261

252262
// go to third step, by jumping over the optional step
253263
navigationMode.goToStep(2);
264+
tick();
265+
wizardTestFixture.detectChanges();
266+
254267
// go back to first step
255268
navigationMode.goToStep(0);
269+
tick();
256270
wizardTestFixture.detectChanges();
257271

258272
const allLi = navBar.queryAll(By.css('li'));
@@ -283,16 +297,20 @@ describe('WizardNavigationBarComponent', () => {
283297
expect(defaultLi[0]).toBe(allLi[2]);
284298

285299
expect(navigableLi.length).toBe(0);
286-
});
300+
}));
287301

288302
it('should show the second step correctly, after first jumping from the first to the third step ' +
289-
'and then back from the third step to the second step', () => {
303+
'and then back from the third step to the second step', fakeAsync(() => {
290304
const navBar = wizardTestFixture.debugElement.query(By.css('wizard-navigation-bar'));
291305

292306
// go to third step, by jumping over the optional step
293307
navigationMode.goToStep(2);
308+
tick();
309+
wizardTestFixture.detectChanges();
310+
294311
// go back to second step
295312
navigationMode.goToPreviousStep();
313+
tick();
296314
wizardTestFixture.detectChanges();
297315

298316
const allLi = navBar.queryAll(By.css('li'));
@@ -324,14 +342,16 @@ describe('WizardNavigationBarComponent', () => {
324342

325343
expect(navigableLi.length).toBe(1);
326344
expect(navigableLi[0]).toBe(allLi[0]);
327-
});
345+
}));
328346

329-
it('should disable navigation through the navigation bar correctly', () => {
347+
it('should disable navigation through the navigation bar correctly', fakeAsync(() => {
330348
const navBar = wizardTestFixture.debugElement.query(By.css('wizard-navigation-bar'));
331349

332350
wizardState.disableNavigationBar = true;
351+
333352
// go to third step and jump over the optional second step
334353
navigationMode.goToStep(2);
354+
tick();
335355
wizardTestFixture.detectChanges();
336356

337357
const allLi = navBar.queryAll(By.css('li'));
@@ -362,55 +382,67 @@ describe('WizardNavigationBarComponent', () => {
362382
expect(defaultLi.length).toBe(0);
363383

364384
expect(navigableLi.length).toBe(0);
365-
});
385+
}));
366386

367-
it('should move back to the first step from the second step, after clicking on the corresponding link', () => {
387+
it('should move back to the first step from the second step, after clicking on the corresponding link', fakeAsync(() => {
368388
const goToFirstStepLink = wizardTestFixture.debugElement.query(By.css('li:nth-child(1) a')).nativeElement;
369389

370390
expect(wizardState.currentStepIndex).toBe(0);
371391

372392
// go to the second step
373393
navigationMode.goToNextStep();
394+
tick();
395+
wizardTestFixture.detectChanges();
396+
374397
expect(wizardState.currentStepIndex).toBe(1);
375398

376399
// go back to the first step
377400
goToFirstStepLink.click();
401+
tick();
378402
wizardTestFixture.detectChanges();
379403

380404
expect(wizardState.currentStepIndex).toBe(0);
381-
});
405+
}));
382406

383-
it('should move back to the first step from the third step, after clicking on the corresponding link', () => {
407+
it('should move back to the first step from the third step, after clicking on the corresponding link', fakeAsync(() => {
384408
const goToFirstStepLink = wizardTestFixture.debugElement.query(By.css('li:nth-child(1) a')).nativeElement;
385409

386410
expect(wizardState.currentStepIndex).toBe(0);
387411

388412
// go to the second step
389413
navigationMode.goToStep(2);
414+
tick();
415+
wizardTestFixture.detectChanges();
416+
390417
expect(wizardState.currentStepIndex).toBe(2);
391418

392419
// go back to the first step
393420
goToFirstStepLink.click();
421+
tick();
394422
wizardTestFixture.detectChanges();
395423

396424
expect(wizardState.currentStepIndex).toBe(0);
397-
});
425+
}));
398426

399-
it('should move back to the second step from the third step, after clicking on the corresponding link', () => {
427+
it('should move back to the second step from the third step, after clicking on the corresponding link', fakeAsync(() => {
400428
const goToSecondStepLink = wizardTestFixture.debugElement.query(By.css('li:nth-child(2) a')).nativeElement;
401429

402430
expect(wizardState.currentStepIndex).toBe(0);
403431

404432
// go to the second step
405433
navigationMode.goToStep(2);
434+
tick();
435+
wizardTestFixture.detectChanges();
436+
406437
expect(wizardState.currentStepIndex).toBe(2);
407438

408439
// go back to the first step
409440
goToSecondStepLink.click();
441+
tick();
410442
wizardTestFixture.detectChanges();
411443

412444
expect(wizardState.currentStepIndex).toBe(1);
413-
});
445+
}));
414446

415447
it('should not move to the second step from the first step, after clicking on the corresponding link', () => {
416448
const goToFirstStepLink = wizardTestFixture.debugElement.query(By.css('li:nth-child(1)'));

0 commit comments

Comments
 (0)