ngModelChange ou change - resolvido

Assim ele não funciona.

<input
              matInput
              [formControlName]="'quantidadeEstoque'"
              [readonly]="ver"
              (change)="calculoCustoQuantidadeEstoque()"
              currencyMask
              [options]="{
                prefix: '',
                suffix: '',
                thousands: '.',
                decimal: ',',
                precision: 5
              }"
            />

Só funciona assim:

<input
              matInput
              [formControlName]="'quantidadeEstoque'"
              [readonly]="ver"
              (ngModelChange)="calculoCustoQuantidadeEstoque()"
              currencyMask
              [options]="{
                prefix: '',
                suffix: '',
                thousands: '.',
                decimal: ',',
                precision: 5
              }"
            />

O que preciso é que quando ele sai do componente ele chama o metodo calculoCustoQuantidadeEstoque() e não quando digita algo

change é um evento do DOM, enquanto que ngModelChange é um evento do angular, amarrado ao model. Prefira ngModelChange.

1 curtida

entendi.

Mas como fazer para utilizar o (change)=“calculoCustoQuantidadeEstoque()”, neste caso ?

O (change)=“calculoCustoQuantidadeEstoque()”, só funciona se o componente ficar assim.

<input
matInput
[formControlName]=“‘quantidadeEstoque’”
[readonly]=“ver”
(change)=“calculoCustoQuantidadeEstoque()”
/>

Mas no meu caso preciso que o campo só aceite casas decimais com até 5 caracteres.

Estou com um problema assim:

image

Ao digitar no campo Quantidade de venda ele altera o quantidade de estoque, ele chama este método:
HTML
>

        <mat-label>Quantidade de venda *</mat-label>
        <input
          matInput
          [formControlName]="'quantidadeVenda'"
          [readonly]="ver"
          currencyMask
          [options]="{
            prefix: '',
            suffix: '',
            thousands: '.',
            decimal: ',',
            precision: 5
          }"
          (ngModelChange)="calculoCustoQuantidadeVenda($event)"
        />
        <mat-icon
          *ngIf="inserir"
          matSuffix
          style="cursor: pointer"
          pTooltip="Digitando a quantidade de venda o valor do campo Quantidade de estoque é alterado !"
        >
          info
        </mat-icon>
      </mat-form-field>

typescript

 async calculoCustoQuantidadeVenda(valor: any): Promise<any> {
    this.temUnidadePorDerivacao = false;
    this.formGroup.controls.quantidadeEstoque.disable();
    this.calculouValor = false;
    await this.novoFormGroupValorPraticado();
    if (
      valor !== undefined &&
      valor !== null &&
      valor !== "" &&
      valor !== 0 &&
      this.formGroup.controls.custo.value !== undefined &&
      this.formGroup.controls.custo.value !== null &&
      this.formGroup.controls.custo.value !== "" &&
      this.formGroup.controls.custo.value !== 0 &&
      this.formGroup.controls.quantidadeVenda.status === "VALID"
    ) {   
     const quantidade = await this.calculoDerivacao(true);
      this.formGroup.controls.quantidadeEstoque.setValue(quantidade);
      this.formGroup.controls.quantidadeEstoque.enable();
      this.formGroup.controls.quantidadeVenda.enable();
      await this.ajusteTela();
    } else {
      this.formGroup.controls.quantidadeEstoque.enable();
      await this.ajusteTela();
    }
  }

Ao digitar no campo Quantidade de estoque ele altera o quantidade de venda, com este método:
HTML

<mat-form-field class="w-full sm:w-60 mt-4 sm:mt-0 sm:ml-4">
            <mat-label>Quantidade de estoque *</mat-label>
            <input
              matInput
              [formControlName]="'quantidadeEstoque'"
              [readonly]="ver"
              currencyMask
              [options]="{
                prefix: '',
                suffix: '',
                thousands: '.',
                decimal: ',',
                precision: 5
              }"
              (ngModelChange)="calculoCustoQuantidadeEstoque($event)"
            />
            <mat-icon
              *ngIf="inserir"
              matSuffix
              style="cursor: pointer"
              pTooltip="Digitando a quantidade de estoque o valor do campo Quantidade de venda é alterado !"
            >
              info
            </mat-icon>
          </mat-form-field>

typescript

async calculoCustoQuantidadeEstoque(valor: any): Promise<any> {
    this.temUnidadePorDerivacao = false;
    this.formGroup.controls.quantidadeVenda.disable();
    this.calculouValor = false;
    await this.novoFormGroupValorPraticado();
    if (
      valor !== undefined &&
      valor !== null &&
      valor !== "" &&
      valor !== 0 &&
      this.formGroup.controls.custo.value !== undefined &&
      this.formGroup.controls.custo.value !== null &&
      this.formGroup.controls.custo.value !== "" &&
      this.formGroup.controls.custo.value !== 0 &&
      this.formGroup.controls.quantidadeEstoque.status === "VALID"
    ) {
      const quantidade = await this.calculoDerivacao(false);
      this.formGroup.controls.quantidadeVenda.setValue(quantidade);
      this.formGroup.controls.quantidadeVenda.enable();
      this.formGroup.controls.quantidadeEstoque.enable();
      await this.ajusteTela();
    } else {
      this.formGroup.controls.quantidadeVenda.enable();
      await this.ajusteTela();
    }
  }

calculoDerivacao

private async calculoDerivacao(inverso: boolean): Promise<number>{
    let quantidade: number = 0;
      if("SIM" === this.produtoDerivacaoEscolhido.configuracao.calculaPrecoDimensao
      && (
        this.produtoDerivacaoEscolhido.configuracao.idUnidadeMedidaFatoracaoSegunda !== undefined ||
        this.produtoDerivacaoEscolhido.configuracao.idUnidadeMedidaFatoracaoSegunda !== null ||
        this.produtoDerivacaoEscolhido.configuracao.idUnidadeMedidaFatoracaoSegunda !== ""
      )&& (
        this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda !== undefined ||
        this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda !== null ||
        this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda !== ""
      )&& (
        this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda !== undefined ||
        this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda !== null ||
        this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda !== "" ||
        this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda > 0
      )){
        if("MULTIPLICAR" === this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda){
          if(inverso){
            quantidade = this.formGroup.controls.quantidadeVenda.value / this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda;
          } else {
            quantidade = this.formGroup.controls.quantidadeVenda.value * this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda;
          }
        } else if("DIVISAO" === this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda){
          if(inverso){
            quantidade = this.formGroup.controls.quantidadeVenda.value * this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda;
          } else {
            quantidade = this.formGroup.controls.quantidadeVenda.value / this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda;  
          }
        } else if("SOMAR" === this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda){
          if(inverso){
            quantidade = this.formGroup.controls.quantidadeVenda.value - this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda;
          } else {
            quantidade = this.formGroup.controls.quantidadeVenda.value + this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda;
          }
        } else if("SUBTRAIR" === this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda){
          if(inverso){
            quantidade = this.formGroup.controls.quantidadeVenda.value + this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda;
          } else {
            quantidade = this.formGroup.controls.quantidadeVenda.value - this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda;            
          }
        } else {
          quantidade = this.formGroup.controls.quantidadeVenda.value;
        }
      }
      return quantidade;
  }

Só que fica no looping eterno. Como resolver ?

Entendi. Nesse como o evento está aplicado aos dois inputs e um acaba alterando o outro, acaba entrando em loop mesmo. Nunca cai nesse caso, não sei se o angular tem algum mecanismo pronto para tratar essa situação. Pensei em algumas alternativas:

  • Talvez vc possa fazer algum controle usando uma variável extra, por exemplo, indicando que está editando o campo A e que o evento do campo B seja ignorado e vice-e-versa
  • Outra forma poderia tentar usar o evento blur para disparar apenas qdo sair do campo
  • Ou ainda, poderia ter um botão calcular, por exemplo, para executar a lógica em vez de ficar apegado aos eventos.

DICA: Crie uma função de validação para dá uma reduzida no código:

isValid(valor: any): boolean {
  return valor !== undefined && valor !== null && valor !== ""
}

Assim em todo lugar onde estiver fazendo essas verificações, apenas chame: isValid(qualquerValor). Vc tambem pode simplificar apenas com:

if (valor && valor !== 0) {}

que tb funciona.


Dei uma refatorada (com certeza dá para ser melhorado). Veja o que tu acha:

async calculoDerivacao(inverso: boolean): Promise<number> {
  let quantidade: number = 0;

  if (
    "SIM" === this.produtoDerivacaoEscolhido.configuracao.calculaPrecoDimensao 
    && this.isValid(this.produtoDerivacaoEscolhido.configuracao.idUnidadeMedidaFatoracaoSegunda) 
    && this.isValid(this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda) 
    && (this.isValid(this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda) || this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda > 0)
  ) {
    quantidade = this.calcular(
      this.produtoDerivacaoEscolhido.configuracao.tipoConversaoUnidadeSegunda,
      inverso,
      this.formGroup.controls.quantidadeVenda.value,
      this.produtoDerivacaoEscolhido.configuracao.valorConversaoUnidadeSegunda
    )
  }

  return quantidade;
}

private calcular(tipoConversao: string, inverso: boolean, valueA: number, valueB: number): number {
  if (tipoConversao === "MULTIPLICAR") {
    return inverso ? (valueA / valueB) : (valueA * valueB);
  }
  
  if (tipoConversao === "DIVISAO") {
    return inverso ? (valueA * valueB) : (valueA / valueB);
  }
  
  if (tipoConversao === "SOMAR") {
    return inverso ? (valueA - valueB) : (valueA + valueB);
  }
  
  if (tipoConversao === "SUBTRAIR") {
    return inverso ? (valueA + valueB) : (valueA - valueB);
  }

  return valueA;
}

private isValid(valor: any): boolean {
  return valor !== undefined && valor !== null && valor !== ""
}
1 curtida

Este funcionou.

Valeu

1 curtida