Search code examples
javascriptfunctionhandlebars.jsaccounting.js

How to transmit an arguments object to a function?


I'm working with handlebars.js and I'd like to format some numbers with a helper. To format a number I've found the accounting.js library that seems to meet my expectations. To format a number I can use:

// Simple `format` string allows control of symbol position (%v = value, %s = symbol):
accounting.formatMoney(5318008, { symbol: "GBP",  format: "%v %s" }); // 5,318,008.00 GBP

Here is my current helper:

Handlebars.registerHelper('amount', function(item) {
    if (item == null) {
        return "-"; 
    } else {    
        return accounting.formatMoney(item,{symbol: "EUR",  format: "%v %s"});                                       
    }
});

This works but this a bit strict in use, I'd like to be able to format my numbers as an option. My new helper would then be :

Handlebars.registerHelper('amount', function(item, options) {
    if (item == null) {
        return "-"; 
    } else {    
        return accounting.formatMoney(item,options);                                       
    }
});

The problem is that it doesn't work because I don't know how to pass the object to the worker. Here is my call in the template

{{amount programme.amountIssued {symbol: "EUR",  format: "%v %s"} }}

This gives me the following result:

handlebars.js:1659 Uncaught Error: Parse error on line 87:
...gramme.amountIssued {symbol: "EUR",  for
-----------------------^
Expecting 'CLOSE_RAW_BLOCK', 'CLOSE', 'CLOSE_UNESCAPED', 'OPEN_SEXPR', 'CLOSE_SEXPR', 'ID', 'OPEN_BLOCK_PARAMS', 'STRING', 'NUMBER', 'BOOLEAN', 'UNDEFINED', 'NULL', 'DATA', 'SEP', got 'INVALID'

If I use it with quotes around and quotes inside commented with \ :

{{amount programme.amountIssued "{symbol: \"EUR\",  format: \"%v %s\"}" }}

This is executed but the result is not the one expected :

{symbol: "EUR", format: "4,000,000,000.00 %s"}%v

instead of 4,000,000,000.00 EUR


Solution

  • You can't pass arguments to a JS function with an object. But you can pass them as an array. This is done through .apply (docs).

    Wrapped for legibility and including defaults for every option:

    Handlebars.registerHelper('amount', function (item, options) {
        if (item == null) return "-"; 
    
        return accounting.formatMoney.apply(accounting, [
            item,
            options.symbol || "",
            options.precision || 2,
            options.thousands || ".",
            options.decimal || ","
        ]);                                       
    });
    

    Here the function is applied to an array of values (hence the name of the operation) where each array position matches the parameter position the function expects.