Skip to content

Commit 0c9bd9a

Browse files
authored
Remove duplicate can exit calls (#44)
- remove canGoToNextStep and canGoToPreviousStep - moved calling of finalize EventEmitters to the goToStep methods - split finalize callback in preFinalize and postFinalize callbacks - extracted duplicate code from canEnterStep and canExitStep into a common method canTransitionStep - modify the README to reflect the made changes to the finalize
1 parent 3844ceb commit 0c9bd9a

16 files changed

+275
-187
lines changed

README.md

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -307,16 +307,27 @@ that contains to which step a click on the element should change the current ste
307307
This can be useful if your step transitions depend on some application dependent logic, that changes depending on the user input.
308308
Here again it's important to use `[]` around the `goToStep` directive to tell angular that the argument is to be interpreted as javascript.
309309

310+
#### \(preFinalize\)
311+
Sometimes it's required to bind an event emitter to a specific element, which can perform a step transition.
312+
Such an event emitter can be bound to the `(preFinalize)` output of the element, which contains the `goToStep` directive.
313+
This event emitter is then called, directly before the wizard transitions to the given step.
314+
315+
#### \(postFinalize\)
316+
Alternatively you can also bind an event emitter to `(postFinalize)`,
317+
which is executed directly after the wizard transitions to the given step.
318+
310319
#### \(finalize\)
311-
If you want to call a function only after pressing on a element with a `goToStep` directive, you can do this,
312-
by adding the function to the `finalize` attribute of the element with the `goToStep` directive.
320+
In case you don't really care when the finalization event emitter is called, you can also bind it simply to `(finalize)`.
321+
`finalize` is a synonym for `preFinalize`.
313322

314323
#### Parameter overview
315324
Possible parameters:
316325

317326
| Parameter name | Possible Values | Default Value |
318327
| ----------------- | --------------------------------------------------------- | ------------- |
319328
| [goToStep] | WizardStep | StepOffset | number | string | null |
329+
| (preFinalize) | function() | null |
330+
| (postFinalize) | function() | null |
320331
| (finalize) | function() | null |
321332

322333
### \[nextStep\]
@@ -328,16 +339,18 @@ This listener will automatically change the currently selected wizard step to th
328339
```
329340

330341
#### \(finalize\)
331-
Like the `goToStep` directive the `nextStep` directive provides a `finalize` output, that is called every time
342+
Like the `goToStep` directive the `nextStep` directive provides a `preFinalize`, `postFinalize` and `finalize` output, which are called every time
332343
the current step is successfully exited, by clicking on the element containing the `nextStep` directive.
333344

334-
In the given code snipped above, a click on the button with the text `Next Step`, leads to a call of the function `finalizeStep` every time, the button has been pressed.
345+
In the given code snipped above, a click on the button with the text `Next Step`, leads to a call of the `finalize` functions every time, the button has been pressed.
335346

336347
#### Parameter overview
337348
Possible parameters:
338349

339350
| Parameter name | Possible Values | Default Value |
340351
| ----------------- | ------------------------------------------- | ------------- |
352+
| (preFinalize) | function() | null |
353+
| (postFinalize) | function() | null |
341354
| (finalize) | function() | null |
342355

343356
### \[previousStep\]
@@ -349,14 +362,16 @@ This listener will automatically change the currently selected wizard step to th
349362
```
350363

351364
#### \(finalize\)
352-
Like both the `goToStep` and `nextStep` directives the `previousStep` directives too provides a `finalize` output, that is called every time
365+
Like both the `goToStep` and `nextStep` directives the `previousStep` directives too provides a `preFinalize`, `postFinalize` and `finalize` output, which are called every time
353366
the current step is successfully exited, by clicking on the element containing the `previousStep` directive.
354367

355368
#### Parameter overview
356369
Possible parameters:
357370

358371
| Parameter name | Possible Values | Default Value |
359372
| ----------------- | ------------------------------------------- | ------------- |
373+
| (preFinalize) | function() | null |
374+
| (postFinalize) | function() | null |
360375
| (finalize) | function() | null |
361376

362377
### \[wizardStep\]

src/directives/go-to-step.directive.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ import {NavigationMode} from '../navigation/navigation-mode.interface';
1515
<wizard>
1616
<wizard-step stepTitle='Steptitle 1' [canExit]="canExit">
1717
Step 1
18-
<button type="button" goToStep="0" (finalize)="finalizeStep(1)">Stay at this step</button>
19-
<button type="button" [goToStep]="goToSecondStep" (finalize)="finalizeStep(1)">Go to second step</button>
20-
<button type="button" [goToStep]="{stepOffset: 2}" (finalize)="finalizeStep(1)">Go to third step</button>
18+
<button type="button" goToStep="0" (preFinalize)="finalizeStep(1)">Stay at this step</button>
19+
<button type="button" [goToStep]="goToSecondStep" (preFinalize)="finalizeStep(1)">Go to second step</button>
20+
<button type="button" [goToStep]="{stepOffset: 2}" (preFinalize)="finalizeStep(1)">Go to third step</button>
2121
</wizard-step>
2222
<wizard-step stepTitle='Steptitle 2' optionalStep>
2323
Step 2
@@ -26,7 +26,7 @@ import {NavigationMode} from '../navigation/navigation-mode.interface';
2626
</wizard-step>
2727
<wizard-step stepTitle='Steptitle 3'>
2828
Step 3
29-
<button type="button" [goToStep]="{stepOffset: -2}" (finalize)="finalizeStep(3)">Go to first step</button>
29+
<button type="button" [goToStep]="{stepOffset: -2}" (postFinalize)="finalizeStep(3)">Go to first step</button>
3030
</wizard-step>
3131
</wizard>
3232
`

src/directives/go-to-step.directive.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,38 @@ import {NavigationMode} from '../navigation/navigation-mode.interface';
4040
})
4141
export class GoToStepDirective {
4242
/**
43-
* An EventEmitter to be called when this directive is used to exit the current step.
44-
* This EventEmitter can be used to do cleanup work
43+
* This [[EventEmitter]] is called directly before the current step is exited during a transition through a component with this directive.
4544
*
4645
* @type {EventEmitter}
4746
*/
4847
@Output()
49-
public finalize = new EventEmitter();
48+
public preFinalize: EventEmitter<void> = new EventEmitter();
49+
50+
/**
51+
* This [[EventEmitter]] is called directly after the current step is exited during a transition through a component with this directive.
52+
*
53+
* @type {EventEmitter}
54+
*/
55+
@Output()
56+
public postFinalize: EventEmitter<void> = new EventEmitter();
57+
58+
/**
59+
* A convenience name for `preFinalize`
60+
*
61+
* @param {EventEmitter<void>} emitter The [[EventEmitter]] to be set
62+
*/
63+
@Output()
64+
public set finalize(emitter: EventEmitter<void>) {
65+
/* istanbul ignore next */
66+
this.preFinalize = emitter;
67+
}
68+
69+
/**
70+
* A convenience field for `preFinalize`
71+
*/
72+
public get finalize(): EventEmitter<void> {
73+
return this.preFinalize;
74+
}
5075

5176
/**
5277
* The destination step, to which the wizard should navigate, after the component, having this directive has been activated.
@@ -103,10 +128,6 @@ export class GoToStepDirective {
103128
* After this method is called the wizard will try to transition to the `destinationStep`
104129
*/
105130
@HostListener('click', ['$event']) onClick(): void {
106-
if (this.navigationMode.canGoToStep(this.destinationStep)) {
107-
this.finalize.emit();
108-
109-
this.navigationMode.goToStep(this.destinationStep);
110-
}
131+
this.navigationMode.goToStep(this.destinationStep, this.preFinalize, this.postFinalize);
111132
}
112133
}

src/directives/next-step.directive.spec.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ import {NavigationMode} from '../navigation/navigation-mode.interface';
1313
<wizard-step stepTitle='Steptitle 1'>
1414
Step 1
1515
<button type="button" nextStep (finalize)="finalizeStep(1)">Go to second step</button>
16+
<button type="button" nextStep (postFinalize)="finalizeStep(1)">Go to second step</button>
1617
</wizard-step>
1718
<wizard-step stepTitle='Steptitle 2'>
1819
Step 2
19-
<button type="button" nextStep (finalize)="finalizeStep(2)">Go to third step</button>
20+
<button type="button" nextStep (postFinalize)="finalizeStep(2)">Go to first step</button>
2021
</wizard-step>
2122
</wizard>
2223
`
@@ -58,7 +59,7 @@ describe('NextStepDirective', () => {
5859
expect(wizardTestFixture.debugElement.query(
5960
By.css('wizard-step[stepTitle="Steptitle 2"] > button[nextStep]'))).toBeTruthy();
6061
expect(wizardTestFixture.debugElement.queryAll(
61-
By.css('wizard-step > button[nextStep]')).length).toBe(2);
62+
By.directive(NextStepDirective)).length).toBe(3);
6263
});
6364

6465
it('should move correctly to the next step', () => {
@@ -80,22 +81,41 @@ describe('NextStepDirective', () => {
8081
expect(wizardState.currentStepIndex).toBe(1);
8182
});
8283

83-
it('should move call finalize correctly when going the next step', () => {
84-
const firstStepButton = wizardTestFixture.debugElement.query(
85-
By.css('wizard-step[stepTitle="Steptitle 1"] > button[nextStep]')).nativeElement;
86-
const secondStepButton = wizardTestFixture.debugElement.query(
87-
By.css('wizard-step[stepTitle="Steptitle 2"] > button[nextStep]')).nativeElement;
84+
it('should call finalize correctly when going the next step', () => {
85+
const firstStepButtons = wizardTestFixture.debugElement.queryAll(
86+
By.css('wizard-step[stepTitle="Steptitle 1"] > button[nextStep]'));
8887

8988
expect(wizardTest.eventLog).toEqual([]);
9089

9190
// go to second step
92-
firstStepButton.click();
91+
firstStepButtons[0].nativeElement.click();
92+
93+
expect(wizardTest.eventLog).toEqual(['finalize 1']);
94+
});
95+
96+
it('should call postFinalize correctly when going the next step', () => {
97+
const firstStepButtons = wizardTestFixture.debugElement.queryAll(
98+
By.css('wizard-step[stepTitle="Steptitle 1"] > button[nextStep]'));
99+
100+
expect(wizardTest.eventLog).toEqual([]);
101+
102+
// go to second step
103+
firstStepButtons[1].nativeElement.click();
93104

94105
expect(wizardTest.eventLog).toEqual(['finalize 1']);
106+
});
107+
108+
it('shouldn\'t call finalize when going to an nonexistent step', () => {
109+
const secondStepButton = wizardTestFixture.debugElement.query(
110+
By.css('wizard-step[stepTitle="Steptitle 2"] > button[nextStep]')).nativeElement;
111+
112+
navigationMode.goToStep(1);
113+
114+
expect(wizardTest.eventLog).toEqual([]);
95115

96116
// don't go to third step because it doesn't exist
97117
secondStepButton.click();
98118

99-
expect(wizardTest.eventLog).toEqual(['finalize 1']);
119+
expect(wizardTest.eventLog).toEqual([]);
100120
});
101121
});

src/directives/next-step.directive.ts

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,38 @@ import {WizardState} from '../navigation/wizard-state.model';
1818
})
1919
export class NextStepDirective {
2020
/**
21-
* An EventEmitter to be called when this directive is used to exit the current step.
22-
* This EventEmitter can be used to do cleanup work
21+
* This [[EventEmitter]] is called directly before the current step is exited during a transition through a component with this directive.
2322
*
2423
* @type {EventEmitter}
2524
*/
2625
@Output()
27-
public finalize = new EventEmitter();
26+
public preFinalize: EventEmitter<void> = new EventEmitter();
27+
28+
/**
29+
* This [[EventEmitter]] is called directly after the current step is exited during a transition through a component with this directive.
30+
*
31+
* @type {EventEmitter}
32+
*/
33+
@Output()
34+
public postFinalize: EventEmitter<void> = new EventEmitter();
35+
36+
/**
37+
* A convenience name for `preFinalize`
38+
*
39+
* @param {EventEmitter<void>} emitter The [[EventEmitter]] to be set
40+
*/
41+
@Output()
42+
public set finalize(emitter: EventEmitter<void>) {
43+
/* istanbul ignore next */
44+
this.preFinalize = emitter;
45+
}
46+
47+
/**
48+
* A convenience field for `preFinalize`
49+
*/
50+
public get finalize(): EventEmitter<void> {
51+
return this.preFinalize;
52+
}
2853

2954
/**
3055
* The navigation mode
@@ -47,10 +72,6 @@ export class NextStepDirective {
4772
* After this method is called the wizard will try to transition to the next step
4873
*/
4974
@HostListener('click', ['$event']) onClick(): void {
50-
if (this.navigationMode.canGoToNextStep()) {
51-
this.finalize.emit();
52-
53-
this.navigationMode.goToNextStep();
54-
}
75+
this.navigationMode.goToNextStep(this.preFinalize, this.postFinalize);
5576
}
5677
}

src/directives/previous-step.directive.spec.ts

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,22 @@ import {NavigationMode} from '../navigation/navigation-mode.interface';
1212
<wizard>
1313
<wizard-step stepTitle='Steptitle 1'>
1414
Step 1
15-
<button type="button" previousStep>Go to zero step</button>
15+
<button type="button" (finalize)="finalizeStep(1)" previousStep>Go to zero step</button>
1616
</wizard-step>
1717
<wizard-step stepTitle='Steptitle 2'>
1818
Step 2
19-
<button type="button" previousStep>Go to first step</button>
19+
<button type="button" (finalize)="finalizeStep(2)" previousStep>Go to first step</button>
20+
<button type="button" (postFinalize)="finalizeStep(2)" previousStep>Go to first step</button>
2021
</wizard-step>
2122
</wizard>
2223
`
2324
})
2425
class WizardTestComponent {
26+
public eventLog: Array<string> = [];
27+
28+
finalizeStep(stepIndex: number): void {
29+
this.eventLog.push(`finalize ${stepIndex}`);
30+
}
2531
}
2632

2733
describe('PreviousStepDirective', () => {
@@ -53,7 +59,7 @@ describe('PreviousStepDirective', () => {
5359
expect(wizardTestFixture.debugElement.query(
5460
By.css('wizard-step[stepTitle="Steptitle 2"] > button[previousStep]'))).toBeTruthy();
5561
expect(wizardTestFixture.debugElement.queryAll(
56-
By.css('wizard-step > button[previousStep]')).length).toBe(2);
62+
By.directive(PreviousStepDirective)).length).toBe(3);
5763
});
5864

5965
it('should move correctly to the previous step', () => {
@@ -80,4 +86,44 @@ describe('PreviousStepDirective', () => {
8086

8187
expect(wizardState.currentStepIndex).toBe(0);
8288
});
89+
90+
it('should call finalize correctly when going the previous step', () => {
91+
const secondStepButtons = wizardTestFixture.debugElement.queryAll(
92+
By.css('wizard-step[stepTitle="Steptitle 2"] > button[previousStep]'));
93+
94+
navigationMode.goToStep(1);
95+
96+
expect(wizardTest.eventLog).toEqual([]);
97+
98+
// go to second step
99+
secondStepButtons[0].nativeElement.click();
100+
101+
expect(wizardTest.eventLog).toEqual(['finalize 2']);
102+
});
103+
104+
it('should call postFinalize correctly when going the previous step', () => {
105+
const secondStepButtons = wizardTestFixture.debugElement.queryAll(
106+
By.css('wizard-step[stepTitle="Steptitle 2"] > button[previousStep]'));
107+
108+
navigationMode.goToStep(1);
109+
110+
expect(wizardTest.eventLog).toEqual([]);
111+
112+
// go to second step
113+
secondStepButtons[1].nativeElement.click();
114+
115+
expect(wizardTest.eventLog).toEqual(['finalize 2']);
116+
});
117+
118+
it('shouldn\'t call finalize when going to an nonexistent step', () => {
119+
const firstStepButton = wizardTestFixture.debugElement.query(
120+
By.css('wizard-step[stepTitle="Steptitle 1"] > button[previousStep]')).nativeElement;
121+
122+
expect(wizardTest.eventLog).toEqual([]);
123+
124+
// don't go to third step because it doesn't exist
125+
firstStepButton.click();
126+
127+
expect(wizardTest.eventLog).toEqual([]);
128+
});
83129
});

0 commit comments

Comments
 (0)