Converting user input into a bunch of numbers based on predefined business logic is usually a common task. I came across a problem where the output of the users input was transformed and put back into the input.
The problem with data, which is getting processed by a function twice, is that it leads to inconsistent results. Especially if you feed that data back into the input element, while the input process is in progress.
The issue with a naive apporch
Let's have a look at the core issue of our problem. Our title should be cleaned up (transformed) on the fly. Let's have a look at a bad example.
Since the user keeps typing while we are processing his input, we override his data with our "clean" version of his input. Thie user experience suffers a lot. The cursor jumps back and forth and some characters are missing.
The Quest
Let's imagine that we want to create a simple calculation helper component to convert prices based on a predifined business logic. We want to convert prices from per km to per ton and per transport depending on the users source of input.
We are going to transform all the other values, except the provided one. Since it's the source of truth in that particular moment. Which prevents wild rendering/racing issues with the input itself (like described before).
Since our calculation depends on some base values which might change if we calculate different prices eg. retail, purchase, it's probably better to enclose our calculation inside a class.
Our class has to perform calculations, holding the raw input value and cleanup our values for presentation purposes (rounding).
We round the calculated values, except the provided one. In some cases the calculations could lead to some crazy numbers like 13.6666666666666667 and we don't want to show them to the user.
Rounding issues are a sacrifice, we can accept at this point.
The getters are a way to allways get the presentation value.
classPrice{// distance in meters// payload in kilogramsconstructor(base ={ distance:0, payload:0}){this.base= base;this.perKm=0;this.perTransport=0;this.perTon=0;}// Rounding numbers with fixed precisionpreciseFloat(num, precision =2){returnparseFloat(parseFloat(num).toFixed(precision));}setPerKm(priceKm){this.perKm= priceKm;this.perTransport=this.preciseFloat(priceKm *this.base.distance/1000);this.perTon=this.preciseFloat(this.perTransport/this.base.payload*1000);}setPerTransport(priceTransport){this.perTransport= priceTransport;this.perKm=this.preciseFloat(priceTransport /this.base.distance*1000);this.perTon=this.preciseFloat(priceTransport /this.base.payload*1000);}setPerTon(priceTon){this.perTon= priceTon;this.perTransport=this.preciseFloat(priceTon *this.base.payload/1000);this.perKm=this.preciseFloat(this.perTransport/this.base.distance*1000);}getPerKm(){if(!this.perKm)return0;returnthis.preciseFloat(this.perKm);}getPerTransport(){if(!this.perTransport)return0;returnthis.preciseFloat(this.perTransport);}getPerTon(){if(!this.perTon)return0;returnthis.preciseFloat(this.perTon);}}
Our Price class can be used to perform similar operations with a different data base. For example, retail and purchase prices, which have the same base but different values.
Hey there! I'm Johannes aka Scribblerockerz, a fullstack developer from Germany. Most of the time
I'm trying to convert concepts into code.
Hit me up on twitter
if you want to talk!