1

In my react app, I'm receiving a cost (like 990.00) from the API as a string. I'm storing it in a material UI table with sorting function. To sort the cost, it should be in number format. I'm using toFloat() to convert it to a number but I get 900 only. If I modify it to toFloat().toFixed(2), it will be convert again into a string. If I modify it to toFloat().round(2), no output at all.

var cost = '900.00'
var numericCost = toFloat(cost) //type - number but no decimal zeros
var numericCost = toFloat(cost).toFixed(2) //type - string, so can't sort it
var numericCost = toFloat(cost).round(2) //no output (can't see the data)

How do I get that number with type - number with following decimal zeros ?

Here is the Sorting method:

let counter = 0;
function createData(projectId, projectName, projectStatus, totalCost, paymentStatus, clientName, email, phone) {
    counter += 1;
    return { id: counter, projectId, projectName, projectStatus, totalCost, paymentStatus, clientName, email, phone };
}

function desc(a, b, orderBy) {
    if (b[orderBy] < a[orderBy]) {
        return -1;
    }
    if (b[orderBy] > a[orderBy]) {
        return 1;
    }
    return 0;
}

function getSorting(order, orderBy) {
    return order === 'desc' ? (a, b) => desc(a, b, orderBy) : (a, b) => -desc(a, b, orderBy);
}

class AllTable extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            order: 'asc',
            orderBy: 'userName',
            data: [],
        };
    }

componentDidMount() {
        API.get('url')
            .then(({ data }) => {
                this.setState({
                    data: data.response.map(
                        job => (
                            createData(
                                job.project_id,
                                parseFloat(job.total),
                                job.payment_status,
                            )
                        )
                    )
                })
            })
            .catch((err) => {
                console.log("AXIOS ERROR: ", err);
            })
    }

handleRequestSort = (event, property) => {
        const orderBy = property;
        let order = 'desc';
        if (this.state.orderBy === property && this.state.order === 'desc') {
            order = 'asc';
        }
        this.setState({ order, orderBy });
    };

    render(){
      return(
          {data
            .sort(getSorting(order, orderBy))
               .map(n => {
                  return (
                    <TableRow
                        hover
                        tabIndex={-1}
                        key={n.id}
                    >
                       <TableCell className={classes.tdWidth}><div className={classes.cellWidth}>${n.totalCost}</div></TableCell>
                       <TableCell className={classes.tdWidth}><div className={classes.cellWidth}>{n.paymentStatus}</div></TableCell>
                    </TableRow>
           })}
      )
}

}
David Johns
  • 1,254
  • 3
  • 19
  • 48
  • 4
    You don't; a number cannot store following zeros. This is most likely an XY problem, please tell us what your goal is. –  May 16 '19 at 08:00
  • In JS there's just Number. – Walk May 16 '19 at 08:01
  • 1
    please add the sorting part. btw, where is `toFloat` from? – Nina Scholz May 16 '19 at 08:02
  • 1
    `but I get 900 only` thats what you have. – Jonas Wilms May 16 '19 at 08:02
  • 1
    I don't see the issue tbh; 1. api response 2. parse to float 3. sort 4. output as `toFixed(2)` –  May 16 '19 at 08:03
  • 3
    Possible duplicate of [javascript number precision without converting to String](https://stackoverflow.com/questions/21711600/javascript-number-precision-without-converting-to-string) and [How can I round a number in JavaScript? .toFixed() returns a string?](https://stackoverflow.com/questions/2283566) – adiga May 16 '19 at 08:03
  • @ChrisG I updated the question with my react component. I need to sort the cost column and costs need to be in numbers (a currency) – David Johns May 16 '19 at 08:44
  • @NinaScholz I added the sorting part – David Johns May 16 '19 at 08:44
  • If what you **really** want is a number representing currency, then there's a [DOM API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NumberFormat) for that. – vsync May 16 '19 at 08:46
  • 1
    Did you see my [previous comment](https://stackoverflow.com/questions/56163628/how-to-convert-numbers-from-string-to-float-with-following-zeros-in-javascript?noredirect=1#comment98954650_56163628)? It's not necessary at all to create a number with following zeros. You sort the number, then call `toFixed(2)` on it when you display it. –  May 16 '19 at 09:21

3 Answers3

1

The core issue you're trying to solve is sorting by some version of the number (a numeric value), and then displaying another (a string, with defined precision). The solution is to separate out those two concerns, such that you're not using the same value to both sort and display:

render() {
  let data = this.props.data.sort((a, b) => {
    // This is the sorting function, so we need to treat the values as a number
    return toFloat(a.cost) - toFloat(b.cost);
  });

  return data.map(n => {
    // Now we're showing the data, so treat it as a string
    // It's already a string fetched from the API in the format needed, so just use directly
    return (
      <TableRow key={n.id}>
        <TableCell>{n.cost}</TableCell>
      </TableRow>
    );
  });
}
MidnightLightning
  • 6,715
  • 5
  • 44
  • 68
0

So i will reformule my Answer, toFixed always returns a string number because in javascript decimals can't be represented in binary floating-point systems with full accuracy, for example 10.2 is in fact 10.2........ (many numbers after decimal point)

so to fixed cuts a part of the number as a string in order to give us the result that we want with precision.

in order to fix this you need to create your own function, and here's a link to help you: https://exoboy.wordpress.com/2011/07/14/the-problems-with-tofixed-in-javascript/

you will need the following code: (i'm not the owner of the code i got it from the link that i mentionned)

Number.prototype.trimNum = function(places,rounding){

(rounding != 'floor' && rounding != 'ceil') ? rounding = 'round' : rounding = rounding;

var result, num = this, multiplier = Math.pow( 10,places );

result = Math[rounding](num * multiplier) / multiplier;

return Number( result );

}

so to call this function you just have to use num.trimNum( places, rounding ); where places are number of places after decimal point, and rounding is a string value ('round'/'ceil'/'floor')

This will solve your problem in most of the cases, but in your case '999.00' it will still show 999,but it won't affect the result because 999 and 999.00 will have the same result

-1

Try this:

var cost = '900.00'
var numericCost = parseFloat(cost).toFixed(2)
shim
  • 9,289
  • 12
  • 69
  • 108
  • Please read the question: "*If I modify it to toFloat().toFixed(2), it will be convert again into a string*" – adiga May 16 '19 at 08:10