0

Just starting to use JavaScript Classes and have a quick question. In the example below, I want to ensure/convert certain properties to be numeric when I create the class. For instance, if the user enters "$10.50" for the unit price, I want the class to only have 10.50 so the total function works. I'm sure this can be done with a getter/setter but I can't quite figure out how to implement it.

    <form name="orderform">
      order date: <input name="order_date" value="" type=text>
      <br>item_name: <input name="item_name" value="" type=text>
      <br>unit_price: <input name="unit_price" value="" type=text>
      <br>quantity: <input name="quantity" value="0" type=text>
    </form>
class OrderItem {
  constructor(
    order_date,
    item_name,
    unit_price,
    quantity,
  ) {
    this.order_date = order_date;
    this.item_name = item_name;
    this.unit_price = unit_price;
    this.quantity = quantity;    
  }
  get total() {
    return this.unit_price * this.quantity;
  }
}


const orderitem1 = new OrderItem();



function GetNumber(val)
{
  if (typeof val !== 'undefined')
  {
      return Number(val.replace(/[^0-9.-]+/g, ""));
  }
  else
  {
    return 0;
  } 
}



function getOrder()
{
  $("#orderform").serializeArray().map(function(x){orderitem1[x.name] = x.value;}); 
  
  var total = orderitem.total;  //doesn't work if they enter '$10.50'

//...do stuff here with the orderitem1 class....
}
3
  • 1
    Maybe I'm misunderstanding the question, but why not this.unit_price = GetNumber(unit_price), etc. in the constructor? Commented Feb 7, 2022 at 22:06
  • Hi ray, I tried that but it never changed "$10.50" from the form to 10.50 in the unit_price property in the class. It just stayed at "$10.50". That's why I thought maybe I did it incorrectly. Commented Feb 7, 2022 at 22:09
  • @MikeSmith Please show us how you are constructing the class, otherwise we can't help you fix the code Commented Feb 7, 2022 at 23:37

1 Answer 1

1

Instead of creating the OrderItem and then updating its values in getOrder, you could create the OrderItem on the spot.

The snippet below instantiates an OrderItem from the form data on submit, and parses the numeric values in the constructor using your existing GetNumber function.

You could also consider changing the input type from 'text' to 'number' for those inputs, which would (mostly) prevent users from entering $ in the first place.

// get a reference to the form
const form = document.querySelector('form[name=orderform]');

// add an onsubmit handler
form.addEventListener('submit', (e) => {
  // stop the form from submitting
  e.preventDefault();
  
  // convert the form's inputs into a key-value mapping, e.g. { quantity: "12", unit_price: "$10.50", ... }
  const data = new FormData(e.target);
  const config = [...data.entries()].reduce((acc, [key, value]) => ({...acc, [key]: value}), {})
  
  // instantiate an OrderItem from the config
  const orderItem = new OrderItem(config);
  
  // do whatever you need to do with it
  console.log(orderItem.total);
})

class OrderItem {
  constructor({
    order_date,
    item_name,
    unit_price,
    quantity,
  } = {}) {
    this.order_date = order_date;
    this.item_name = item_name;
    this.unit_price = GetNumber(unit_price);
    this.quantity = GetNumber(quantity);
  }
  get total() {
    return this.unit_price * this.quantity;
  }
}


function GetNumber(val) {
  if (typeof val !== 'undefined') {
    return Number(val.replace(/[^0-9.-]+/g, ""));
  } else {
    return 0;
  }
}
<form name="orderform">
  order date: <input name="order_date" value="" type=text>
  <br>item_name: <input name="item_name" value="" type=text>
  <br>unit_price: <input name="unit_price" value="$10.50" type=text>
  <br>quantity: <input name="quantity" value="1" type=text>
  <button>Get Order</button>
</form>

alternative

If for some reason you need to be able to change the OrderItem's values after instantiating it, you could do it in a getter or setter. (But generally speaking immutability is A Good Thing™.)

class OrderItem {
  set unit_price(p) {
    // needs a different internal name to avoid recursion
    this._unitPrice = toNumber(p);
  }
  
  get unit_price() {
    return this._unitPrice;
  }
}

const toNumber = v => Number(`${v}`.replace(/[^0-9.]/g, ''));

const item = new OrderItem();
item.unit_price = '$10.50';

console.log(item.unit_price);

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks Ray. To clarify, I can't just instantiate on submit because I need to compare it to some other orders on the same page for validation purposes. Is there a way one can mix the constructor like I have with the set/get that you show in the alternative scenario?
Sure. I omitted the constructor from the second example for clarity (and laziness), but you could put it in there and it would work. Just need to keep in mind that the internal property needs a distinct name from the setter to avoid the setter invoking itself.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.