我意识到我的问题是我对可观察性和RxJS非常了解。
我有一个这样的自定义验证器:
export function ValidateFinalQty(service: MyService) {
return (control: AbstractControl): { [key: string]: any } | null => {
let qty = service.GetQty();
if (control.value != qty) {
return { FinalQuantityNotMatching: true };
} else {
return null;
}
};
}
GetQty返回一个RxJS Observable。
那么,如何设置它,以便我的同步验证器根据异步调用返回正确的值?我需要验证器的返回类型保持为{ [key: string]: any } | null
。
我看到了类似qty = await service.GetQty().first().toPromise();
之类的建议,但是随后我返回了一个承诺,并且我无法为我所理解的验证者返回一个承诺。
我该如何处理?
来自我的package.json
:
"@angular/core": "7.1.0",
"@angular/forms": "7.1.0",
"rxjs": "6.3.3",
"rxjs-compat": "^6.4.0",
UPDATE 5/23/19尝试实现@Sachin的答案。 我在地图内的断点永远不会被击中。我没有任何控制台日志,即使我删除了映射中的逻辑并返回null,它仍然始终返回无效。对于这里发生的事情非常困惑。我已经确认了我的服务。
有什么想法吗?
export class CustomAsyncValidator {
static ValidateFinalQty(qtyService: FinalQtyService, brf: BatchRecordForm): AsyncValidatorFn {
return (control: AbstractControl) => {
return qtyService.postCalcFinalQuanity(brf)
.pipe(
map((qty) => {
console.log("running qty validator. value:", qty);
if (control.value !== qty) {
return { FinalQuantityNotMatching: true };
} else {
return null;
}
}),
catchError((err) => {
console.log("Error in final quantity validator", err);
return null;
}),
finalize(() => console.log("finished"))
);
};
}
}
答案 0 :(得分:1)
我有一种类似的Validator指令,请根据您的代码进行调整:
看看它是否对您有用
import { Directive } from '@angular/core';
import { NG_ASYNC_VALIDATORS, AsyncValidator, AbstractControl, ValidationErrors } from '@angular/forms';
import { MyService } from './MyService';
import { Observable, of as observableOf} from 'rxjs';
@Directive({
selector: '[qty-valid]',
providers: [{provide: NG_ASYNC_VALIDATORS, useExisting: QuantityValidatorDirective , multi: true}]
})
export class QuantityValidatorDirective implements AsyncValidator {
constructor(private service : MyService ) { }
validate(control: AbstractControl): Promise<ValidationErrors | null> | Observable<ValidationErrors | null> {
return new Promise((resolve, reject) => {
this.service.GetQty()
.subscribe( (qty: any) => {
if (control.value != qty) {
resolve({ FinalQuantityNotMatching: true })
} else {
resolve(null)
}
},error => resolve(null));
});
}
}
答案 1 :(得分:1)
希望这会有所帮助
export class CustomAsyncValidator {
static ValidateFinalQty(apiService: ApiService):AsyncValidatorFn {
return (control: AbstractControl) => {
const value = control.value;
return apiService.GetQty()
.pipe(
take(1),
map(qty => {
if (value!=qty) {
return { FinalQuantityNotMatching: true };
} else {
return null;
}
})
);
};
}
}
使用方法
this.yourForm = this.fb.group({
yourField: ["",CustomValidator.ValidateFinalQty(this.apiService)]
});
答案 2 :(得分:1)
在您的验证器发送异步RxJS调用时,最好使用AsyncValidator
(另请参阅我为您创建的有效的demo)
从文档中
constructor(formState:any = null,validatorOrOpts ?: ValidatorFn | AbstractControlOptions | ValidatorFn [],asyncValidator ?: AsyncValidatorFn | AsyncValidatorFn [])
如您所见,您可以将AsyncValidatorFn
作为第三个参数传递给FormControl。
假设getQty()
返回的Observable发出您需要比较的值。您的自定义验证程序将如下所示:
custom.validator.ts
import { AbstractControl } from '@angular/forms';
import { MyService } from './my.service';
import { map } from 'rxjs/operators';
export class ValidateFinalQty {
static createValidator(myService: MyService) {
return (control: AbstractControl) => {
return myService.getQty().pipe(map(res => {
return control.value == res ? null : { FinalQuantityNotMatching: true };
}));
};
}
}
在这里我创建了一个静态方法,该方法将接受您的服务并执行调用,并在条件不匹配时给出错误。
我在您的代码中注意到的一件事是,不是订阅getQty()
返回的Observable,而是将其值分配给qty
变量,这不是处理Observable的正确方法。您可以了解有关可观察物here
现在在您的组件中:
import { Component, OnInit } from '@angular/core';
import { FormGroup, Validators, FormBuilder } from '@angular/forms'
import { ValidateFinalQty } from './custom.validator';
import { MyService } from './my.service';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit{
name = 'Angular';
myForm: FormGroup
constructor(private myService: MyService, private fb: FormBuilder) {
}
ngOnInit() {
this.myForm = this.fb.group({
quantity: [
'',
[Validators.required],
ValidateFinalQty.createValidator(this.myService)
]
});
}
}
并在您的HTML中:
<form [formGroup]="myForm">
<label>Quantity</label>
<input type="number" formControlName="quantity" placeholder="Enter quantity to validate">
<div *ngIf="myForm.get('quantity').status === 'PENDING'">
Checking...
</div>
<div *ngIf="myForm.get('quantity').status === 'VALID'">
? Quantity is valid!
</div>
<div *ngIf="myForm.get('quantity').errors && myForm.get('quantity').errors.FinalQuantityNotMatching">
? Oh noes, your quantity is not valid!
</div>
</form>
<small>5 is valid quantity for the sake of example</small>
希望有帮助。