Angular - os formulários reativos têm estado pendente

Oct 21 2020

Estou em um projeto angular e estou usando uma forma reativa. O que estou tentando fazer é adicionar meu próprio validador. Para fazer isso, preciso verificar se a id existe no banco de dados. Por esse motivo, uso um validador assíncrono. Caso o id já esteja sendo usado por outro elemento, ele deve retornar um erro. Caso contrário, o formulário será válido.

Este é o validador.

    export class ValidadorOperationId {
      static createValidatorOperationId(name, operationListService: OperationsListService, time: number = 500): AsyncValidatorFn {
        return (control: AbstractControl): Observable<ValidationErrors> => {
          return timer(time).pipe(
            switchMap(() => operationListService.getOperationsByUuid(name, control.value)),
            map(res => {
              return res ? { operationIdExist: true } : null
              }
            )
          );
        };
      }
    }

E é assim que chamo o validador no meu componente.

 this.fb.group({
   value: [this.operationDetails['operationid'], [Validators.required], ValidadorOperationId.createValidatorOperationId(this.nombre,this.operationListService)]
 })

O problema é que o controle tem status: pendinge não sei o que está errado.

Se você precisar de mais algum código, é só me perguntar.

Alguém pode me ajudar?

  • Versão Angular: 8.2.14
  • Versão Rxjs: 6.5.3

ATUALIZAÇÃO 22/10/2020

Verifiquei que status:pendingsó aparece quando o serviço não retorna nada (erro 404)

Respostas

1 QuentinFonck Oct 22 2020 at 16:24

Certifique-se de getOperationsByUuidretornar pelo menos um valor observável ou uma promessa, mesmo quando você receber um erro 404. Essa pode ser a razão pela qual ele ficou preso no estado pendente porque esta função não retorna nada, então seu observável não emite.
Observe o operador de torneira. Se este log não for impresso, é por isso que fica pendente, porque nunca resolve.

    export class ValidadorOperationId {
      static createValidatorOperationId(name, operationListService: OperationsListService, time: number = 500): AsyncValidatorFn {
        return (control: AbstractControl): Observable<ValidationErrors> => {
          return timer(time).pipe(
            switchMap(() => operationListService.getOperationsByUuid(name, control.value)),
            tap(res => console.log('this should print')),
            map(res => {
              return res ? { operationIdExist: true } : null
              }
            ),
            take(1) // not useful if getOperationsByUuid is an http call (http calls always complete)
          );
        };
      }
    }
1 Akash Oct 22 2020 at 16:57

Para manipular 404ou qualquer outro erro de http, você pode usar o operador catchError do RxJS . Abaixo está a aparência do seu validador -

export class ValidadorOperationId {
      static createValidatorOperationId(name, operationListService: OperationsListService, time: number = 500): AsyncValidatorFn {
        return (control: AbstractControl): Observable<ValidationErrors> => {
          return timer(time).pipe(
            switchMap(() => operationListService.getOperationsByUuid(name, control.value)
           .pipe(catchError(err => of(null))), // <-- this is what you need
            map(res => {
              return res ? { operationIdExist: true } : null
              }
            )
          );
        };
      }
    }