
Para criar uma interface amigável, você precisa garantir que todos os formulários em seu aplicativo se comportem de maneira consistente. O comportamento monótono é freqüentemente alcançado por código repetitivo, embora de forma implícita. Deixe-me compartilhar um esboço de um padrão que eu acho que simplifica o desenvolvimento e padroniza o comportamento do formulário.
Se o código para enviar formulários em seu projeto for semelhante a este, aconselho você a procurar em cat.
onSubmit (): void
// login.component.ts
// bad practices
onSubmit(): void {
this.formSubmitted = true;
this.isUnhandledServerError = false;
if (!this.formGroup.valid) return;
this.isLoading = true;
const { username, password } = this.formGroup.value;
this.login(username, password)
.pipe(finalize(() => (this.isLoading = false)))
.subscribe({ error: error => this.handleError(error) });
}
Para aqueles que adoram código:
Projete no stackblitz antes de refatorar.
Projeto Stackblitz após refatoração.
Descrição do problema
Os formulários requerem que muitas nuances sejam levadas em consideração. Do ponto de vista funcional, o formulário apenas envia as informações inseridas pelo usuário para o servidor. Mas para garantir uma UX de alta qualidade, além de tudo, você tem que fazer a validação, exibir os erros do servidor, um indicador de carregamento, etc. Na prática, esses detalhes são muitas vezes esquecidos pelos desenvolvedores, o que afeta negativamente a usabilidade do aplicativo ou resulta em duplicação de código e torna o desenvolvimento de formulários uma rotina intolerável.
Aqui está um exemplo de um manipulador de envio de formulário que é bom do ponto de vista da experiência do usuário, mas ruim do ponto de vista do desenvolvimento. Projeto Stackblitz antes da refatoração.
// login.component.ts
onSubmit(): void {
this.formSubmitted = true; //
this.isUnhandledServerError = false; //
if (!this.formGroup.valid) return; //
this.isLoading = true; //
const { username, password } = this.formGroup.value;
this.login(username, password) //
.pipe(finalize(() => (this.isLoading = false))) //
.subscribe({ error: error => this.handleError(error) });
}
Como você pode ver, esse manipulador leva em consideração muitos detalhes que compõem a UX. O único problema é que, com essa abordagem, essas nuances terão que ser escritas para cada formulário do aplicativo.
Decisão
Para simplificar o desenvolvimento e padronizar o comportamento dos formulários em seu aplicativo, você precisa mover o código do manipulador de envio do formulário para uma classe separada. Projeto Stackblitz após refatoração. (Eu simplifiquei intencionalmente o código do exemplo; em um projeto real, você precisa substituir todos os campos booleanos por Observáveis.)
class Form<T> {
submitted = false;
pending = false;
hasUnhandledServerError = false;
constructor(private formGroup: FormGroup, private action: (value: any) => Observable<T>) {}
submit(): Observable<T> {
if (this.pending) return EMPTY;
this.submitted = true;
this.hasUnhandledServerError = false;
if (this.formGroup.valid) {
this.pending = true;
return this.action(this.formGroup.value).pipe(
tap({ error: () => (this.hasUnhandledServerError = true) }),
finalize(() => (this.pending = false)),
);
}
return EMPTY;
}
}
Assim, concentramos a maioria dos recursos de UX em uma classe e nos livramos da lógica duplicada. Agora, escrever um novo formulário levará menos tempo e você pode concluir o comportamento dos formulários em todo o aplicativo, alterando apenas a classe Form.
Por que não colocá-lo na biblioteca?
Os requisitos de UX para cada projeto são únicos e mais dependentes do designer. Já tive que substituir o comportamento dos elementos materiais padrão a pedido do cliente. Portanto, não vejo nenhuma maneira de padronizar o comportamento dos formulários em todos os aplicativos que usam uma biblioteca. Deixe o comportamento da interface ficar à mercê do designer e dos desenvolvedores. No entanto, acho uma boa ideia separar a lógica relacionada à UX em classes diferentes.
Espero que o exemplo tenha sido útil e que você tente usar a ideia em seus projetos. Enquanto!