About the Author

**Johannes Schröder**@Scribblerockerz

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!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.

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**.

`<input :value="title" @input="cleanupInput">`

```
cleanupInput(e) {
this.title = someCleanupFunction(e.target.value);
}
```

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.

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.

*Explore the concept on codesandbox.io*

The price type and conversion method is driven by the users input choice, we have to handle all of our three combinations differently.

```
<input :value="perKm" @input="convertByKm">
<input :value="perTransport" @input="convertByTransport">
<input :value="perTon" @input="convertByTon">
```

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

```
convertByKm(priceKm) {
this.perKm = priceKm;
this.perTransport = priceKm * DISTANCE;
this.perTon = this.perTransport / PAYLOAD;
}
convertByTransport(priceTransport) {
this.perKm = priceTransport / DISTANCE;
this.perTransport = priceTransport;
this.perTon = priceTransport / PAYLOAD;
}
convertByTon(priceTon) {
this.perTransport = priceTon * PAYLOAD;
this.perKm = this.perTransport / DISTANCE;
this.perTon = priceTon;
}
```

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.

```
class Price {
// distance in meters
// payload in kilograms
constructor(base = { distance: 0, payload: 0 }) {
this.base = base;
this.perKm = 0;
this.perTransport = 0;
this.perTon = 0;
}
// Rounding numbers with fixed precision
preciseFloat(num, precision = 2) {
return parseFloat(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) return 0;
return this.preciseFloat(this.perKm);
}
getPerTransport() {
if (!this.perTransport) return 0;
return this.preciseFloat(this.perTransport);
}
getPerTon() {
if (!this.perTon) return 0;
return this.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.

```
export default {
data() {
return {
baseData: { distance: 2000, payload: 5000 },
retail: null,
purchase: null,
}
},
created() {
this.retail = new Price(this.baseData);
this.purchase = new Price(this.baseData);
this.retail.setPerTransport(2000);
this.purchase.setPerTransport(1000);
}
}
```

We are going to use the all of our 3 parts of the class for every value.

`purchase.perKm`

is the raw input value, or a calculated product of our computation.`purchase.setPerKm(...)`

is the update method, which sets our input value (since we provided the value itself) and recalculates all the other values.`purchase.getPerKm()`

is the presentation value.

```
<!-- KM -->
<input
:value="purchase.perKm"
type="number"
@input="purchase.setPerKm($event.target.value)"
/>
<div>{{ purchase.getPerKm() }} € / km</div>
<!-- TRANSPORT -->
<input
:value="purchase.perTransport"
type="number"
@input="purchase.setPerTransport($event.target.value)"
/>
<div>{{ purchase.getPerTransport() }} € / Transport</div>
<!-- TON -->
<input
:value="purchase.perTon"
type="number"
@input="purchase.setPerTon($event.target.value)"
>
<div>{{ purchase.getPerTon() }} € / t</div>
```

Play around with the final concept on codesandbox.io.

This small pattern is a solution to an *uncommon problem*. If you have any questions or a different way to solve that issue, hit me up on twitter.