Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

Erro ao utilizar injectDOM decorator.

Estou tendo problema ao usar o decorator injectDOM. Ele não está injetando o elemento para as propriedades. Sinceramente tentei debugar bastante mas não consegui achar o problema. Se alguém puder me ajudar, agradeço. Segue snippets do codigo.

export function domInjector(selector: string) {
  return function (target: any, propertyKey: string) {
    console.log(`Modificando protype ${target.constructor.name}
           e adicionando getter para a propriedade ${propertyKey}`);
    console.log(selector);

    let element: HTMLElement;

    const getter = function () {
      console.log(
        `Modificando prototype ${target.constructor.name} e adicionando getter para a propriedade ${propertyKey}`
      );
      element = <HTMLElement>document.getElementById(selector);
      console.log(
        `buscando elemento do DOM com o seletor ${selector} para injetar em ${propertyKey}`
      );
      return element;
    };
    Object.defineProperty(target, propertyKey, { get: getter });
  };
}
import { domInjector } from "../decorators/dom-injector.js";
import { inspectMethod } from "../decorators/inspect-method.js";
import { logExecutionTime } from "../decorators/log-execution-time.js";
import { WeekDays } from "../enums/week-days.js";
import { Negotiation } from "../models/negotiation.js";
import { Negotiations } from "../models/negotiations.js";
import { MessageView } from "../views/message-view.js";
import { NegotiationsView } from "../views/negotiations-view.js";

export class NegotiationController {
  //BUG
  @domInjector("data")
  private _inputDate: HTMLInputElement;
  //BUG
  @domInjector("quantidade")
  private _inputQuantity: HTMLInputElement;
  //BUG
  @domInjector("valor")
  private _inputValue: HTMLInputElement;
  private _negotiations = new Negotiations();
  private _negotationsView = new NegotiationsView("#table-container");
  private _messageView = new MessageView("#mensagemView");

  constructor() {
    //Using the template method of the view to render the table once the controller is created

    //BUG - Trying to substitute these selector with propertie decorator
    /*
    this._inputDate = <HTMLInputElement>document.querySelector("#data");
    this._inputQuantity = <HTMLInputElement>(
      document.querySelector("#quantidade")
    );
    this._inputValue = <HTMLInputElement>document.querySelector("#valor");
    */
    this._negotationsView.update(this._negotiations);
  }

  //Invoke a decorator to test the performance of a function
  @logExecutionTime(true)
  @inspectMethod
  public addNegotiation(): void {
    console.log(this._inputDate); //undefined
    console.log(this._inputQuantity); //undefined
    console.log(this._inputValue); //undefined
    const negotiation = Negotiation.createOf(
      //BUG
      this._inputDate.value,
      this._inputQuantity.value,
      this._inputValue.value
      //BUG
    );
    if (!NegotiationController.isWeekDay(negotiation.date)) {
      this._messageView.update(
        "You can only add negotiations on weekdays",
        negotiation
      );
      return;
    }
    this._negotiations.addNewNegotiation(negotiation);
    this.cleanForm();
    this.updateUi(negotiation);
  }

  //Defining a method to validate if the negotiation was done in a week day - Implemented the week-days enum
  public static isWeekDay(date: Date): boolean {
    return (
      date.getDay() !== WeekDays.SUNDAY && date.getDay() !== WeekDays.SATURDAY
    );
  }

  private cleanForm(): void {
    this._inputDate.value = "";
    this._inputQuantity.value = "";
    this._inputValue.value = "";
    this._inputDate.focus();
  }

  //Creating a method to update all views whenever a new transaction is sent
  private updateUi(negotiation: Negotiation): void {
    //Saying to the view to update everytime we add a new negotiation with the negotiations(model) as a parameter
    this._negotationsView.update(this._negotiations, true);
    this._messageView.update("Transaction added successfully", negotiation);
    setTimeout(() => this._messageView.clearMesasage(), 3000);
  }
}

Ele me retorna o seguinte erro somente quando tendo adicionar uma nova transação:

negotiation-controller.ts:47 Uncaught TypeError: Cannot read properties of undefined (reading 'value')
    at _NegotiationController.addNegotiation (negotiation-controller.ts:47:23)
    at descriptor.value (inspect-method.ts:10:49)
    at descriptor.value (log-execution-time.ts:13:51)
    at HTMLFormElement.<anonymous> (app.ts:10:27)
1 resposta
solução!

Oi Arthur, tudo bem?

Desculpe a demora em retornar.

Entendi que você está tendo problemas ao utilizar o decorator injectDOM em seu código, mais especificamente na hora de injetar o elemento para as propriedades. Vou tentar te ajudar a resolver esse problema.

Primeiramente, vamos entender o que o decorator injectDOM está fazendo. Ele é responsável por buscar um elemento do DOM através do seletor passado como parâmetro e injetá-lo na propriedade decorada. No seu código, ele está sendo utilizado para buscar os elementos que representam as datas, quantidades e valores das negociações.

O erro que você está recebendo indica que as propriedades value dos elementos que foram injetados estão indefinidas. Isso ocorre porque essas propriedades só são definidas depois que o elemento é renderizado no DOM. Como você está tentando acessá-las no momento da criação do controlador, elas ainda não estão definidas e, portanto, são indefinidas.

Uma solução para esse problema é adicionar um método que será chamado após a renderização do controlador e que será responsável por buscar as propriedades injetadas novamente, agora com as propriedades value definidas. Para fazer isso, você pode adicionar um método bindInputs() ao seu NegotiationController e chamar esse método após a renderização do controlador, antes de qualquer ação que utilize as propriedades injetadas.

Veja como ficaria a implementação do método bindInputs() no seu código:

private bindInputs(): void {
  this._inputDate = <HTMLInputElement>document.querySelector("#data");
  this._inputQuantity = <HTMLInputElement>document.querySelector("#quantidade");
  this._inputValue = <HTMLInputElement>document.querySelector("#valor");
}

Agora, para chamar esse método após a renderização do controlador, você pode adicionar uma linha de código ao construtor do NegotiationController:

constructor() {
  this._negotationsView.update(this._negotiations);
  this.bindInputs(); // adiciona essa linha para chamar o método que vai injetar as propriedades novamente
}

Assim, as propriedades injetadas serão buscadas novamente após a renderização do controlador, agora com as propriedades value definidas.

Espero que essa solução ajude a resolver o seu problema.

Um abraço e bons estudos.