60

Is it possible to call a function with arguments with Mustache.js

{{somefunction(somevalue)}}
thank you
Andrew Hare
  • 320,708
  • 66
  • 621
  • 623
sinisa
  • 859
  • 1
  • 6
  • 11

6 Answers6

60

Check out the section on Lambdas at http://mustache.github.com/mustache.5.html

Mustache template block:

{{#someFunction}}someValue{{/someFunction}}

Function block:

someFunction : function () {
  return function(val, render) {
    return "I passed in this value: " + render(val);
  };
}

Output:

I passed in this value: someValue
bluehazetech
  • 1,131
  • 10
  • 10
  • Just a javascript warning, after the return function block, there needs to be a semi-colon (;). Sublime Text's SublimeLinter package picked this up. – Benjamin Kaiser Apr 14 '13 at 11:16
  • 3
    This would only work for me if i changed the function signature to `return function(val, render) {` – dano Jul 09 '13 at 20:30
  • 1
    clarifying the above http://www.levihackwith.com/mustache-js-render-is-not-defined/ – mayorbyrne Nov 01 '13 at 16:30
  • 2
    Note that someValue is a text block and it won't be expanded, so with {{#someFunction}}{{somevalue}}{{/someFunction}}, the function will be passed the string value of "{{some value}}". This is probably a more likely usage case e.g. for formatting dates or currency etc – James Westgate Nov 14 '14 at 09:57
  • @JamesWestgate Isn't the intent of the `render` function to transform the raw string value `val` into the expanded form? – Tim Clemons Jan 12 '16 at 19:57
  • What if I want to pass multiple values? – Kousha Mar 09 '17 at 00:00
  • Is there any way to call a global function in this way or does the function have to be defined within the data? – Pat Niemeyer Jan 20 '18 at 15:00
2

for me this works:

add general function FUNC to json (data):

 data.FUNC = function(){
                return function(val, render){
                    var values = JSON.parse(render(val));
                    return window[values.FUNCNAME].apply(this, values.FUNCARGS);
                };
            };

regular javascript on page:

 function foo(arg1, arg2){
    return "Arg1 is " + arg1 +  " and Arg2 is " + arg2;
};

Mustache template block calling the regular javascript-function with tag-values as arguments:

{{#FUNC}}{"FUNCNAME":"foo", "FUNCARGS":["{{page}}","{{title}}"]}{{/FUNC}}

you also can call a function defined in the json:

{{#calljsfunction}} {{#FUNC}}{"FUNCNAME":"{{calljsfunction}}", "FUNCARGS":["{{page}}","{{title}}"]}{{/FUNC}}{{/calljsfunction}}

Holle
  • 21
  • 2
1

A little work around, you can store the value in the element's id

<button id="{{value}}" onclick="somefunction(id)">Click</button>

<script>    
function somefunction(value){
            
}  
</script>
Giorgio Tempesta
  • 928
  • 12
  • 21
zzzzteam
  • 13
  • 2
1

If you want the script contents to be executed after the markup is inserted nito the dom you should use some library that will do the same like jquery.

Try this out here:

http://jsfiddle.net/anilkamath87/GBP8N/

Also if you want to invoke some other method in your script file. All you need to do is call the function depending on the scope of that function and if it has been preloaded into the dom.

Hope this helps.

P.S: note the escape of the script tag in the template markup

Baz1nga
  • 15,010
  • 3
  • 31
  • 59
  • The idea of Mustache is that you keep your javascript outside the templates, and insert it using the template tags given by Mustache. – Jasper Lankhorst Apr 19 '18 at 08:59
0

As I send my template data from an API vis JSON encoding a function in the JSON is messy so I created a simple function to parse out arbitary function with parameters from the API response to call existing JS functions. The comments below explain the functionality.

The TLDR; function parsing

    $.each(funcs, function (funcName, args) {
        window[funcName].apply(null, args);
    });

The context under which it's used.

api response data

{
    "templatesList": [
        {
            "load_sites": {  // the template key - see load_templates()
                "target": "#main",  // the target css selector
                "append": false,        // whether to append to, or set content of css selector
                "data": {               // mustache template data
                    "sites": [
                        {
                            "siteID": "1",
                            "siteName": "Mr Bean House",
                        },
                        {
                            "siteID": "2",
                            "siteName": "Bob the Builder House",
                        }
                    ]
                },
                "funcs": {   // function to call after template insertion
                    "sites_load": [1, 2]   // function sites_load(1,2);
                }
            }
        }
    ]
}

api reposnse parser function (main.js)

$.each(apiResponse.templatesList, function (ti, templateObject) {   // multiple responses in any API response
    $.each(templateObject, function (templateKey, template) {           // break up each into more readable chunks
        render_template( template.target, templateKey, template.data, template.append, template.funcs );  // call the renderer function
    });
});

renderer function (main.js)

function render_template(target, templateKey, templateData, append, funcs) {
    if (typeof templates_html[templateKey] !== "undefined") {  // see function load_templates()
        if (append) {  // append template
            $(target).append( Mustache.to_html( templates_html[templateKey], templateData ) );
        } else {  // set template as content
            $(target).html( Mustache.to_html( templates_html[templateKey], templateData ) );
        }
        
        // parse functions
        if(funcs){
            $.each(funcs, function (funcName, args) {
                window[funcName].apply(null, args);
            });
        }
    }
}

js function to be called called via API response (main.js)

function sites_load(loadJobs, loadProgress){
    console.log("load jobs for site", loadJobs);
    console.log("load progress for site", loadProgress);
}

templates loader - loads the template html on page load (main.js)

// global
templates_html = {};

// load templates html file using the <script id> for the object keys
function load_templates() {
    templates_html = {};
    $.get("templates.html", function (templates) {
        $(templates).filter("script").each(function (templateIndex, templateHTML) {
            var id = $(templateHTML).attr("id");  // id from script tag
            templates_html[id] = $(th).html(); // assign html content to object key
        });
    });
}

example template (templates.html)

<script id="load_sites" type="text/html">
    {{#sites}}
        <div data-siteid="{{siteID}}">
            {{siteName}}</small>
        </div>
    {{/sites}}
</script>
Andy Gee
  • 2,728
  • 2
  • 21
  • 31
-3

Are you trying to call a function as part of your parsing of the mustache code? or generate output, that would call the JavaScript function? e.g. This would output HTML that would call the function (I believe).

{{#items}}
  <script>{{funcName}}("{{url}}");</script>
{{/items}}
scunliffe
  • 57,883
  • 24
  • 118
  • 156
  • 1
    In my situation I have this i.e:

    {{something}}

    , as something is: var something=function(){return "a"}; when i render template its calling variable that is a function... so i got "a" in place of {{something}}... but now i need arguments and thats what im searching for
    – sinisa May 18 '11 at 17:55
  • If you're going to insert ` – Emile Bergeron Mar 14 '16 at 14:55