eliseumds
4/19/2015 - 2:03 PM

Number formatter

Number formatter

import numeral from 'numeral';
import NumberFormattingStrategy from './NumberFormattingStrategy';

class NumeraljsFormatFormattingStrategy extends NumberFormattingStrategy {
    constructor(formatString) {
        super();
        this.formatString = formatString;
    }

    format(value) {
        NumberFormattingStrategy._assertValidValue(value);
        return numeral(value).format(this.formatString);
    }
}
class NumberFormattingStrategy {
    // TODO move to a helper
    static _assertValidValue(value) {
        if (typeof value !== 'number' && typeof value !== 'string') {
            throw new TypeError('`value` must be a number or string');
        }

        value = Number(value);

        if (isNaN(value)) {
            throw new TypeError('`value` must be a valid number');
        }

        return true;
    }

    format() {
        throw 'MethodNotImplementedException';
    }
}
import numeral from 'numeral';
import NumberFormattingStrategy from './strategies/NumberFormattingStrategy';

class NumberFormatter {
    static PLAIN = new NumeraljsFormatFormattingStrategy('0,0');
    static AVG = new NumeraljsFormatFormattingStrategy('0,0.00');
    static PERCENT = new NumeraljsFormatFormattingStrategy('0.0 %');
    static AVG_PERCENT = new NumeraljsFormatFormattingStrategy('0.00 %');

    /**
     * @param  {number|string} value
     * @return {string}
     */
    _parseValue(value) {
        NumberFormattingStrategy._assertValidValue(value);
        return numeral(value);
    }

    /**
     * @param  {string} format
     * @return {function}
     */
    createCallback(format) {
        return this.format.bind(this, format);
    }

    /**
     * @param  {NumberFormattingStrategy} strategy
     * @return {function}
     */
    createCallbackUsing(strategy) {
        return this.formatUsing.bind(this, strategy);
    }

    /**
     * @param  {string} formatString
     * @param  {Date|string|moment} value
     * @return {string}
     */
    format(formatString, value) {
        return this._parseValue(value).format(formatString);
    }

    /**
     * @param  {NumberFormattingStrategy} strategy
     * @param  {number|string}            value
     * @return {string}
     * @throws {TypeError}
     */
    formatUsing(strategy, value) {
        if (strategy instanceof NumberFormattingStrategy) {
            return strategy.format(this._parseValue(value));
        }

        throw new TypeError(
            '`strategy` must be an instance of NumberFormattingStrategy'
        );
    }
}

Number Formatter: how to use

// some pre-made formatters
var myFormatFn = NumberFormatter.PERCENT; // check NumberFormatter.js for more
myFormatFn(0.54122); // '54.1%'
myFormatFn('0.54122'); // '54.1%'

var formatter = new NumberFormatter();

var myStr = formatter.format('0.0', 12.23); // '12.2'

// callbacks?
var myChartSettings = {
    yAxisFormatter: formatter.createCallback('0.0')
};

// with a custom strategy
var myStr = formatter.formatUsing(new CustomStrategy(), 12.984);

CustomNumberFormatter

This subclass gives you more flexibility with pre and post process functions.

Example: let's say you have an API that returns wind speed in meters/second and you want to format it as km/h with one decimal place:

var formatter = new CustomNumberFormatter(
    '0.0',
    value => value * 3.6, // Pre: value here is still the number
    value => value + ' km/h' // Post: value here is already the formatter str
);

var myStr = formatter.format(10); // '36 km/h'