Reputation: 2594
I'm working on a simple stepper
but I'm stuck on how to handle an event within
ng-content. I've tried with a directive with no luck.
I'd like using appStepperNext and appStepperBack to
handle the click event to navigate within the different steps
I put it in the StepComponent but I'd like to handle it in
the StepperComponent
stepper
import {
AfterContentInit,
Component,
ContentChildren,
QueryList
} from '@angular/core';
import { StepComponent } from './step/step.component';
@Component({
selector: 'app-stepper',
template: `
<ul class="stepper">
<ng-container *ngFor="let step of steps; let i = index; let last = last">
<li (click)="selectStep(step)">
<button mat-mini-fab color="primary" [disabled]="!step.active">
{{ i + 1 }}
</button>
</li>
<li class="line" *ngIf="!last"></li>
</ng-container>
</ul>
<ng-content></ng-content>
`,
styleUrls: ['./stepper.component.scss']
})
export class StepperComponent implements AfterContentInit {
@ContentChildren(StepComponent) steps: QueryList<StepComponent>;
// contentChildren are set
ngAfterContentInit() {
// get all active steps
const activeSteps = this.steps.filter(step => step.active);
// if there is no active step set, activate the first
if (activeSteps.length === 0) {
this.selectStep(this.steps.first);
}
}
selectStep(step: StepComponent) {
// deactivate all steps
this.steps.toArray().forEach(step => {
step.active = false;
});
// activate the step the user has clicked on.
step.active = true;
}
}
step
import {
AfterContentInit,
Component,
ContentChildren,
Input,
QueryList
} from '@angular/core';
import { StepperNextDirective } from './stepper-next.directive';
@Component({
selector: 'app-step',
template: `
<div [hidden]="!active">
<ng-content></ng-content>
</div>
`,
styleUrls: ['./step.component.scss']
})
export class StepComponent implements AfterContentInit {
@Input() active = false;
@ContentChildren(StepperNextDirective) dirs: QueryList<StepperNextDirective>;
ngAfterContentInit() {
console.log(this.dirs);
}
}
Dir
import { Directive } from '@angular/core';
@Directive({
selector: '[stepperNext]'
})
export class StepperNextDirective {
constructor() { }
}
Usage
<app-stepper>
<app-step>
Step 1 Content
<button appStepperNext>Next</button>
</app-step>
<app-step>
Step 2 Content
<button appStepperBack>Back</button>
<button appStepperNext>Next</button>
</app-step>
<app-step>
Step 3 Content
<button appStepperNext>Back</button>
<button mat-button>Submit</button>
</app-step>
</app-stepper>
UPDATE after reply of @Bunyamin Coskuner
import { Directive, HostListener, Attribute } from '@angular/core';
import { IwdfStepperComponent } from './stepper.component';
@Directive({
selector: '[iwdfStepperNext]'
})
export class StepperNextDirective {
@HostListener('click') onClick() {
this.stepper.next(this.current);
}
constructor(
@Attribute('current') public current: number,
private stepper: IwdfStepperComponent
) {}
}
Next
Upvotes: 2
Views: 460
Reputation: 8859
I have created the same component for myself and achieved the exact thing you are trying to do.
Here is how you can do it.
You need to define some events within button directives and inject StepperComponent
.
Also, define a next
method within StepperComponent
.
Also, make sure you don't have a typo within your templates. I've changed selector to [appStepperNext]
@Directive({
selector: '[appStepperNext]'
})
export class StepperNextDirective {
constructor(private _stepper: StepperComponent) { }
@HostListener('click')
onClick() {
this._stepper.next();
}
}
Upvotes: 1