Directive inputs with the new input() signals

Discussão em 'Angular' iniciado por kopy01, Novembro 26, 2024.

  1. kopy01

    kopy01 Guest

    I've successfully migrated my Angular 18 project to Angular 19 and replaced all @Input decorators with the new input() signals. The code works but the test for a directive with input() signals breaks.

    Here is my directive, it just multiplies values of a form group.

    import { Directive, OnInit, input } from "@angular/core";
    import { FormGroup, FormGroupDirective } from "@angular/forms";
    import { FormItem } from "../model/form.model";
    import { UntilDestroy, untilDestroyed } from "@ngneat/until-destroy";

    @UntilDestroy()
    @Directive({
    selector: "[appMultiply]",
    standalone: true,
    })
    export class MultiplyDirective implements OnInit {
    constructor(formGroupDirective: FormGroupDirective) {
    this.form = formGroupDirective.form;
    }

    readonly appMultiply = input<FormItem>();
    readonly formDefinition = input<Array<FormItem>>();

    private form: FormGroup;

    ngOnInit(): void {
    const appMultiply = this.appMultiply();
    if (!appMultiply?.multiply || !this.formDefinition()) {
    return;
    }

    const sourceControl = this.form.get(appMultiply.formControlName);

    if (!sourceControl) {
    return;
    }

    //initial calculation
    this.calculateTargetControlValues(appMultiply, sourceControl.value);

    //wait for source changes
    sourceControl.valueChanges
    .pipe(untilDestroyed(this))
    .subscribe((value) =>
    this.calculateTargetControlValues(this.appMultiply()!, value),
    );
    }

    private calculateTargetControlValues = (
    appMultiply: FormItem,
    sourceValue: number,
    ) => {
    const multiplyByControl = this.form.get(
    appMultiply.multiply!.multiplyByControlName,
    );

    if (!multiplyByControl) {
    return;
    }

    this.formDefinition()!
    .filter((formItem) =>
    this.appMultiply()!.multiply!.targetFormControlNames.includes(
    formItem.formControlName,
    ),
    )
    .forEach((formItem) => {
    const targetControl = this.form.get(formItem.formControlName);
    if (!targetControl) {
    return;
    }
    const result = (sourceValue ?? 0) * (multiplyByControl.value ?? 0);
    targetControl.patchValue(result, { emitEvent: false });
    });
    };
    }


    This is the basic test of the directive:

    import { FormGroupDirective } from "@angular/forms";
    import { MultiplyDirective } from "./multiply.directive";

    describe("MultiplyDirective", () => {
    it("should create an instance", () => {
    const directive = new MultiplyDirective(new FormGroupDirective([], []));
    expect(directive).toBeTruthy();
    });
    });


    And I get this error from Karma : "Error: NG0203: inputFunction() can only be used within an injection context such as a constructor, a factory function, a field initializer, or a function used with runInInjectionContext. Find more at https://angular.dev/errors/NG0203"

    If I replace the 2 input signals with @Input decorator inputs, the test runs successfully. Like this :

    @Input() appMultiply!: FormItem
    @Input() formDefinition!: Array<FormItem>


    What do i do wrong?

    Continue reading...

Compartilhe esta Página