我已成功将 Angular 18 项目迁移到 Angular 19,并用新的 input() 信号替换了所有 @Input 装饰器。代码可以工作,但对带有 input() 信号的指令的测试会中断。
这是我的指令,它只是将表单组的值相乘。
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 });
});
};
}
这是该指令的基本测试:
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();
});
});
我从 Karma 收到此错误:“错误:NG0203:inputFunction() 只能在注入上下文中使用,例如构造函数、工厂函数、字段初始值设定项或与
runInInjectionContext
一起使用的函数。了解更多信息https://angular.dev/errors/NG0203”
如果我用 @Input 装饰器输入替换 2 个输入信号,测试将成功运行。像这样:
@Input() appMultiply!: FormItem
@Input() formDefinition!: Array<FormItem>
我做错了什么?
新信号
input()
要求您使用依赖项注入上下文创建组件。
要使用
TestBed
测试指令,您需要通过主机组件来完成。
@Directive({selector: '[appMultiply]'})
class MultiplyDirective {
...
}
@Component({
imports: [ReactiveFormsModule, MyDirective],
template: `<form [formGroup]="fg" myDir></form>`
})
class TestComponent {
fg= new FormGroup({foo: new FormControl('bar')})
}
const fixture = TestBed.createComponent(TestComponent);
const directive = fixture.debugElement.query(By.directive(MyDirective));
console.log(directive);
expect(directive).toBeDefined();
expect(directive.componentInstance.formGroupDirective).toBeDefined()