Search code examples
javascriptjqueryhandsontable

Handsontable percentage formatting leading decimal point


I think I've found a defect with the way Handsontable formats numeric inputs as percentages (or alternatively accepts invalid input depending on your position on what a valid number is).

If you use a leading decimal point decimal point - the percentage formatting will not work - but the input is accepted as a valid string. This is not consistent with numeral.js where the following input is correctly converted (doc suggests numeral formatting should work):

var string = numeral(.001).format('0,0.00000%');
// outputs 0.1000%

The only way I have found to fix this is to add a beforeChanged event so that it calls parseFloat on the value before any further events are fired. I have a feeling this will slow things down when copy large amounts of data. Can anyone confirm this is a defect or I am configuring things incorrectly?

JS Fiddle is below taken from the Handsontable page - remove the commented out beforeChange to see the fix with a beforeChange event. Simply type in any number number starting with a decimal point.

http://jsfiddle.net/deenairn/kwfkLqn4/4/

document.addEventListener("DOMContentLoaded", function () {

function getCarData() {
    return [{
        car: "Mercedes A 160",
        year: 2011,
        price_usd: 7000,
        price_eur: 7000
    }, {
        car: "Citroen C4 Coupe",
        year: 2012,
        price_usd: 8330,
        price_eur: 8330
    }, {
        car: "Audi A4 Avant",
        year: 2013,
        price_usd: 33900,
        price_eur: 33900
    }, {
        car: "Opel Astra",
        year: 2014,
        price_usd: 5000,
        price_eur: 5000
    }, {
        car: "BMW 320i Coupe",
        year: 2015,
        price_usd: 30500,
        price_eur: 30500
    }];
}

var
container = document.getElementById('example1'),
    hot;

hot = new Handsontable(container, {
    data: getCarData(),
    colHeaders: ['Car', 'Year', 'Price ($)', 'Price (€)'],
    columns: [{
        data: 'car'
        // 1nd column is simple text, no special options here
    }, {
        data: 'year',
        type: 'numeric'
    }, {
        data: 'price_usd',
        type: 'numeric',
        format: '$0,0.00',
        language: 'en' // this is the default locale, set up for USD
    }, {
        data: 'price_eur',
        type: 'numeric',
        format: '0,0.00 $',
        language: 'de' // i18n: use this for EUR (German)
        // more locales available on numeraljs.com
    }],
    beforeChange:
    function(changes, source) {
        alert(changes);   
    }
});

function bindDumpButton() {
    if (typeof Handsontable === "undefined") {
        return;
    }

    Handsontable.Dom.addEvent(document.body, 'click', function (e) {

        var element = e.target || e.srcElement;

        if (element.nodeName == "BUTTON" && element.name == 'dump') {
            var name = element.getAttribute('data-dump');
            var instance = element.getAttribute('data-instance');
            var hot = window[instance];
            console.log('data of ' + name, hot.getData());
        }
    });
}
bindDumpButton();

});

Solution

  • Posted here: https://github.com/handsontable/handsontable/issues/2430, but might as well post here as well:

    I believe the problem is in the numericRenderer [in handsontable.full.js] where it checks if (helper.isNumeric(value)) before applying the formatting. This statement evaluates to false if value contains a leading decimal (".3" for instance). So, you can solve this issue by adding a leading zero:

    (helper.isNumeric('0' + value)) evaluates to true for leading decimals but will still evaluate to false for non-numerals ("0.abaca").