Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

343
Visualizações
How does one calculate an output-value which needs to be updated from various form-control elements by control-specific calculation-rules?

I need some help as I'm fairly new to JavaScript.

I wish to create a function that calculates a membership fee

I tried making a function in JavaScript that checks whether only one option has been selected, but I have no idea how to make it so that I can calculate the fee if a user is eligible for more than one or all discounts. There is no current JS for the age condition yet (between 60 and 80) as I am unsure how to do it.

function feeCalc() {
  var ans = document.getElementById("answer");
  if (document.getElementById('medicalCond-yes').checked) {
    ans.value = calculate('medicalCond-yes');
  }
  if (document.getElementById('empstatus-yes').checked) {
    ans.value = calculate('empstatus-yes');
  }
  if (document.getElementById('empstatus-no').checked) {
    ans.value = calculate('empstatus-no');
  }
  if (document.getElementById('medicalCond-no').checked) {
    ans.value = calculate('medicalCond-no');
  }
}

function calculate(action) {
  var standardRate = 10;
  var ageRate = 0.1;
  var medicalRate = 0.4;
  var unemployedRate = 0.3;
  var result;
  switch (action) {
    case 'medicalcond-yes':
      discount = (standardRate * studentRate);
      result = standardRate - discount;
      break;

    case 'empstatus-yes':
      discount = (standardRate * unemployedRate);
      result = standardRate - discount;
      break;

    case 'empstatus-no':
      result = standardRate;
      break;

    case 'medicalcond-no':
      result = standardRate;
      break;
  }
  return result;
}
<div class="form">
  <label>
    Age
  </label>
  <input type="range" value="50" min="1" max="100" class="slider" id="age"/>
</div>

<div class="form">
  <label>
    Do you have any long-term medical conditions
    that can affect daily life
  </label>
  <br/>
  <input type="radio" name="status" value="yes" id="medicalCond-yes"/>Yes
  <input type="radio" name="status" value="no" id="medicalCond-no"/>No
</div>

<div class="form">
  <label>
    Are you currently employed?
  </label>
  <br/>
  <input type="radio" name="empstatus" value="yes" id="empstatus-yes"/>Yes
  <input type="radio" name="empstatus" value="no" id="empstatus-no"/>No
</div>

<div class="form">
  <label>
    Membership Fee
  </label>
  <br/>
  Total Fee:
  <input type="text" id="answer" readonly/>
  <input type="button" value="Calculate" onclick="feeCalc()"/>
</div>

over 4 years ago · Santiago Trujillo
2 Respostas
Responde à pergunta

0

Instead of switch-case routing into a single branch, you probably want to check through all cases in one go.

function feeCalc() {
  var ans = document.getElementById("answer");
  ans.value = calculateRate();
}

function calculateRate() {
  let discount = 0;
  const age = Number(document.getElementById('age').value);
  if (age >= 60 && age <= 80) {
    discount += 0.1;
  }
  if (document.getElementById('medicalCond-yes').checked) {
    discount += 0.4;
  }
  if (document.getElementById('empstatus-no').checked) {
    discount += 0.3;
  }
  return 1 - discount;
}
<div class="form">
  <label>
    Age
  </label>
  <input type="range" value="50" min="1" max="100" class="slider" id="age"/>
</div>

<div class="form">
  <label>
    Do you have any long-term medical conditions
    that can affect daily life
  </label>
  <br/>
  <input type="radio" name="status" value="yes" id="medicalCond-yes"/>Yes
  <input type="radio" name="status" value="no" id="medicalCond-no"/>No
</div>

<div class="form">
  <label>
    Are you currently employed?
  </label>
  <br/>
  <input type="radio" name="empstatus" value="yes" id="empstatus-yes"/>Yes
  <input type="radio" name="empstatus" value="no" id="empstatus-no"/>No
</div>

<div class="form">
  <label>
    Membership Fee
  </label>
  <br/>
  Total Fee:
  <input type="text" id="answer" readonly/>
  <input type="button" value="Calculate" onclick="feeCalc()"/>
</div>

over 4 years ago · Santiago Trujillo Relatório

0

Even though for the OP's problem it looks like over-engineering, the OP's provided code is nevertheless small enough in order to demonstrate the advantages of (more) generic approaches which are ...

  1. Being forced to work with a clean HTML markup/structure as DOM and/or data base.
  2. Decoupling (validation) code from very (business) case specific data like ... not depending ​anymore ...
    • on very specific DOM-element queries,
    • on "baked in" data for e.g. validation and edge case handling.
  3. On long term base easier to maintain (in terms of changed business data) and to adapt to e.g. new discount options.

Especially the JavaScript code which implements a generic approach/behavior of cause is larger from the beginning than its very explicitly written competitor. But the former does not tend to grow or does not even need to get touched for new discount options or changed discount values. This part gets covered by cleaner more generic (hence reusable) substructures of the also generic calculator superstructure.

In addition such a generic component based approach automatically enables the usage of more than just one component at/within one and the same document.

function parseJson(str) {
  let result;
  try {
    result = JSON.parse(str);
  } catch (exc) {
    result = null;
  }
  return result;
}

function getDevaluationFactorFromRange(formControl, range) {
  let factor = 0;

  range = parseJson(range);
  if (range !== null) {

    const controlValue = parseFloat(formControl.value);
    Object
      .entries(range)
      .some(([devaluationKey, { min, max }]) => {

        let isStopIteration = false;
        if (
          (controlValue >= parseFloat(min)) &&
          (controlValue <= parseFloat(max))
        ) {
          factor = parseFloat(devaluationKey);

          isStopIteration = true;
        }
        return isStopIteration
      });
  }
  return Number.isFinite(factor) ? factor : 0;
}
function getDevaluationFactor(formControl) {
  const { dataset } = formControl;

  let rawRange = dataset.devaluationRange ?? null;
  let rawFactor = dataset.devaluationFactor ?? null;

  let factor = (rawRange !== null)
    ? getDevaluationFactorFromRange(formControl, rawRange)
    : 0;

  factor = (
    (factor === 0) && (rawFactor !== null) && parseFloat(rawFactor)
  ) || factor;

  factor = Number.isFinite(factor) ? factor : 0;

  if (factor !== 0) {
    const { type } = formControl;

    if ((type === 'radio') || (type === 'checkbox')) {
      factor = formControl.checked ? factor : 0;
    }
  }
  return factor;
}

function computeCurrentFee(rootNode, elmFee, baseFee) {
  return Array
    // array from `HTMLFormControlsCollection`
    .from(rootNode.elements)
    // calculate currrent fee from each form element's data
    .reduce((currentFee, formControl) => {

      return currentFee - (baseFee * getDevaluationFactor(formControl));

    }, baseFee);
}
function updateCurrentValueAtBoundFeeContext(/*evt*/) {
  const { rootNode, elmFee, baseFee } = this;

  elmFee.value = computeCurrentFee(rootNode, elmFee, baseFee);
}

function displayCurrentValueAtBoundAgeContext(/*evt*/) {
  const { elmRange, elmOutput } = this;

  elmOutput.value = elmRange.value;
}
function initializeCurrentAgeDisplay(rootNode) {
  const ageNode = rootNode.querySelector('[data-age-range]');
  if (ageNode) {

    const elmRange = ageNode.querySelector('input[type="range"]');
    const elmOutput = ageNode.querySelector('output');

    if (elmRange && elmOutput) {
      const target = { elmRange, elmOutput };

      const boundContextHandler =
        displayCurrentValueAtBoundAgeContext.bind(target);

      elmRange.addEventListener('input', boundContextHandler);
      rootNode.addEventListener('reset', () =>
        // decouple custom dom refresh from the system's one.
        setTimeout(boundContextHandler, 0)
      );

      // display initial age value.
      // // displayCurrentValueAtBoundAgeContext.call(target);
      boundContextHandler();
    }
  }
}

function initializeMembershipFeeCalculator(rootNode) {
  const DEFAULT_BASE_FEE = 10;

  initializeCurrentAgeDisplay(rootNode);

  const elmFeeValue = rootNode.querySelector('[data-fee-value]');

  if (elmFeeValue) {
    const baseFee = parseFloat(rootNode.dataset.baseFee);

    const target = {
      rootNode,
      elmFee: elmFeeValue,
      baseFee: Number.isFinite(baseFee) ? baseFee : DEFAULT_BASE_FEE,
    };
    const boundContextHandler =
      updateCurrentValueAtBoundFeeContext.bind(target);

    rootNode.addEventListener('input', boundContextHandler);
    rootNode.addEventListener('reset', () =>
      // decouple custom dom refresh from the system's one.
      setTimeout(boundContextHandler, 0)
    );

    // compute initial fee value.
    // // updateCurrentValueAtBoundFeeContext.call(target);
    boundContextHandler();

    rootNode.addEventListener('submit', evt => {
      evt.preventDefault();
      return false;
    });
  }
}

function main() {
  document
    .querySelectorAll('form[data-membership-fee-calculator]')
    .forEach(initializeMembershipFeeCalculator);
}
main();
body, form {
  margin: 0;
  padding: 0;
}
form {
  float: left;
  width: 50%;
  margin-top: -2px;
}
fieldset {
  position: relative;
  margin: 0 0 2px 0;
  padding: 0 10px 2px 10px;
}
fieldset p {
  margin: 1px 0 2px 0;
}
fieldset output {
  color: #333;
  font-weight: bolder;
}
label {
  display: inline-block;
}
input[type="range"] {
  width: 70%;
}
[data-age-range] output {
  display: inline-block;
  overflow: hidden;
  max-width: 25%;
  max-height: 1.2em;
  position: relative;
  top: 1px;
}
[type="reset"] {
  position: absolute;
  right: 4px;
  top: -4px;
}
<form data-membership-fee-calculator data-base-fee="10">
  <fieldset data-age-range>
    <legend>
      Age
    </legend>
    <input
      type="range"
      name="age" id="age"
      value="50" min="1" max="100"
      data-devaluation-range='{"0.1":{"min":60,"max":80}}'
    />
    <output for="age">### not yet computed ###</output>
  </fieldset>

  <fieldset>
    <p>
      Do you have any long-term medical conditions
      that can affect daily life?
    </p>
    <label>
      <input
        type="radio"
        name="status"
        value="yes"
        data-devaluation-factor="0.4"
      />
      <span class="label-copy">
        Yes
      </span>
    </label>
    <label>
      <input type="radio" name="status" value="no" />
      <span class="label-copy">
        No
      </span>
    </label>
  </fieldset>

  <fieldset>
    <p>
      Are you currently employed?
    </p>
    <label>
      <input
        type="radio"
        name="empstatus" 
        value="yes"
        data-devaluation-factor="0.3"
      />
      <span class="label-copy">
        Yes
      </span>
    </label>
    <label>
      <input type="radio" name="empstatus" value="no" />
      <span class="label-copy">
        No
      </span>
    </label>
  </fieldset>

  <fieldset>
    <legend>
      Membership Fee
    </legend>
    <label>
      <span class="label-copy">
        Total Fee:
      </span>
      <output data-fee-value>### not yet computed ###</output>
    </label>
    <button type="reset">Restore base fee</button>
  </fieldset>
</form>

<form data-membership-fee-calculator data-base-fee="20">
  <fieldset data-age-range>
    <legend>
      Age
    </legend>
    <input
      type="range"
      name="age" id="age"
      value="21" min="1" max="100"
      data-devaluation-range=
        '{"0.05":{"min":60,"max":69},"0.1":{"min":70,"max":79},"0.2":{"min":80,"max":120}}'
    />
    <output for="age">### not yet computed ###</output>
  </fieldset>

  <fieldset>
    <p>
      Do you have any long-term medical conditions
      that can affect daily life?
    </p>
    <label>
      <input
        type="radio"
        name="status"
        value="yes"
        data-devaluation-factor="0.3"
      />
      <span class="label-copy">
        Yes
      </span>
    </label>
    <label>
      <input type="radio" name="status" value="no" />
      <span class="label-copy">
        No
      </span>
    </label>
  </fieldset>

  <fieldset>
    <p>
      Are you currently employed?
    </p>
    <label>
      <input
        type="radio"
        name="empstatus" 
        value="yes"
        data-devaluation-factor="0.3"
      />
      <span class="label-copy">
        Yes
      </span>
    </label>
    <label>
      <input type="radio" name="empstatus" value="no" />
      <span class="label-copy">
        No
      </span>
    </label>
  </fieldset>

  <fieldset>
    <legend>
      Membership Fee
    </legend>
    <label>
      <span class="label-copy">
        Total Fee:
      </span>
      <output data-fee-value>### not yet computed ###</output>
    </label>
    <button type="reset">Restore base fee</button>
  </fieldset>
</form>

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda