flex-table-card icon indicating copy to clipboard operation
flex-table-card copied to clipboard

Doing math with auto_format: true

Open Nickduino opened this issue 1 year ago • 9 comments

I’d like column 5 to be column 4 multiplied by 43 (the price of a liter multiplied by the capacity = the price of a full tank).

It works if I don’t use auto_format :

image

Not with it true:

image

Just in case, I tried :

image

I’m sure some of you will tell me it works exactly as expected but I can assure you, as a user (and not a Javascript developer or a computer wizard of some sort), it’s extremely disconcerting. Should I turn auto_format off and then apply a modify: to each column to replace the . with a , and add the unit?

Nickduino avatar Nov 23 '24 12:11 Nickduino

auto_format happens very early - in fact the data is already received formatted from HA. This means inside modify you'll have a string already - doing arithmetic on strings is not liked by JS:

a = "3 hdf"
"3 hdf"
>> a*4
NaN 

So under the line this boils down to the order of operations done on the data. Maybe you should take a look into suffix (which is appended after modify): https://github.com/custom-cards/flex-table-card/blob/master/docs/example-cfg-simple-cell-formatting.md

It feels like we should document these orders to avoid this confusion...

daringer avatar Nov 27 '24 21:11 daringer

I'd like to fix this problem by grabbing both unformatted and formatted versions and making the unformatted version available for cross-cell math, sorting, footers, etc. The need for unformatted data keeps popping up in issues.

Haven't looked at it in detail yet but I will.

EdLeckert avatar Nov 27 '24 22:11 EdLeckert

I'd like to fix this problem by grabbing both unformatted and formatted versions and making the unformatted version available for cross-cell math, sorting, footers, etc. The need for unformatted data keeps popping up in issues.

Haven't looked at it in detail yet but I will.

But then the cell in which you did cross-cell math won't be formatted, right?

Could the card do the formatting itself (grab the locale from HA and format the data once it's been modified, suffixed and everything)?

Nickduino avatar Nov 28 '24 10:11 Nickduino

But then the cell in which you did cross-cell math won't be formatted, right?

The card can grab both formatted and unformatted values from HA and provide one or the other as appropriate.

In the meantime, you can use parseFloat:

let x = "1.682 €";
console.log (((parseFloat(x)) * 43).toFixed(1));
> "72.3"

The reason this works in this case is:

parseFloat() is more lenient than Number() because it ignores trailing invalid characters, which would cause Number() to return NaN.

parseFloat

EdLeckert avatar Nov 28 '24 18:11 EdLeckert

But then the cell in which you did cross-cell math won't be formatted, right?

The card can grab both formatted and unformatted values from HA and provide one or the other as appropriate.

Some cells will be formatted (the ones without math), the others won't.

In the meantime, you can use parseFloat:

let x = "1.682 €";
console.log (((parseFloat(x)) * 43).toFixed(1));
> "72.3"

The reason this works in this case is:

parseFloat() is more lenient than Number() because it ignores trailing invalid characters, which would cause Number() to return NaN.

I tried:

image

It doesn't work at all:

  1. It doesn't do the math, I get 55 instead of 55*1,8 (or whatever the price per liter is);
  2. the second column loses its format anyway.

image

Nickduino avatar Nov 29 '24 15:11 Nickduino

Apparently parseFloat doesn't support commas as a decimal separator.

The characters accepted by parseFloat() are plus sign (+), minus sign (- U+002D HYPHEN-MINUS), decimal digits (0 – 9), decimal point (.), exponent indicator (e or E), and the "Infinity" literal.

So, you'll have to convert the comma to a period, and then you would have to reformat it:

let x = "1,682 €";
let result =  new Intl.NumberFormat('fr',).format((((parseFloat(x.replace(',', '.'))) * 43).toFixed(1))) + ' €';
console.log(result);
> "72,3 €"

It's not pretty, but it works.

EdLeckert avatar Nov 29 '24 18:11 EdLeckert

Thank you for spending time on my problem!

We're getting somewhere:

image

It's already really good but I'd like to force the number of decimals to 3 on the first column and 2 on the second one.

I tried modify: (new Intl.NumberFormat('fr',).format(parseFloat(x))).toFixed(3), modify: new Intl.NumberFormat('fr', { minimumFractionDigits: 3 } ).format(parseFloat(x)) to no avail

Nickduino avatar Nov 29 '24 21:11 Nickduino

As I said, you're not going to get anywhere trying to parseFloat a number with a comma as a decimal separator.

BTW, I used "fr" to force the locale to French for the example, since my environment is set to "en-US".

let x = "1,8";
let y = 55;
console.log(new Intl.NumberFormat('fr',{minimumFractionDigits:3}).format(parseFloat(x.replace(',', '.'))) + "€/l");
console.log(new Intl.NumberFormat('fr',{minimumFractionDigits:2}).format((parseFloat(x.replace(',', '.') * y))) + "€");
> "1,800€/l"
> "99,00€"

EdLeckert avatar Nov 30 '24 20:11 EdLeckert

As I said, you're not going to get anywhere trying to parseFloat a number with a comma as a decimal separator.

I know, so I had not set auto_format: to true. So I didn't need x.replace(',', '.') since x was already using a decimal point. My mistake (and I thank you for allowing me to realize it) was the space in minimumFractionDigits: 3

So, with modify: Intl.NumberFormat('fr',{ minimumFractionDigits:3 }).format(parseFloat(x)), I get: image

Thanks again!!

Nickduino avatar Dec 03 '24 17:12 Nickduino