user3887366
user3887366

Reputation: 2594

angular how to handle event inside ng-content

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

Answers (1)

Bunyamin Coskuner
Bunyamin Coskuner

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

Related Questions