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....
}
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>
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);