7

I use Handlebars .NET for my mail templates so i generate template at server side width ASP.NET MVC. I need a comparision like this. But it doest't work? What can I do?

//Product.ProdType is a enum property 

{{#if (Product.ProdType=='BlaBlaBla')}}
<p>This is a test</p>
{{/if}}
Dejan
  • 9,150
  • 8
  • 69
  • 117
Yargicx
  • 1,704
  • 3
  • 16
  • 36

4 Answers4

9

I had the same problem and I created a helper function "ifCond" that works with numeric data types and string. It can be optimized or expanded to work with other types.

Handlebars.RegisterHelper("ifCond",
        (writer, context, args) =>
        {
            if (args.Length != 5)
            {
                writer.Write("ifCond:Wrong number of arguments");
                return;
            }

            if (args[0] == null || args[0].GetType().Name == "UndefinedBindingResult")
            {
                writer.Write("ifCond:args[0] undefined");
                return;
            }
            if (args[1] == null || args[1].GetType().Name == "UndefinedBindingResult")
            {
                writer.Write("ifCond:args[1] undefined");
                return;
            }
            if (args[2] == null || args[2].GetType().Name == "UndefinedBindingResult")
            {
                writer.Write("ifCond:args[2] undefined");
                return;
            }

            if (args[0].GetType().Name == "String")
            {
                string val1 = args[0].ToString();
                string val2 = args[2].ToString();

                switch (args[1].ToString())
                {
                    case ">":
                        writer.Write(val1.Length > val2.Length ? args[3] : args[4]);
                        break;
                    case "=":
                    case "==":
                        writer.Write(val1 == val2 ? args[3] : args[4]);
                        break;
                    case "<":
                        writer.Write(val1.Length < val2.Length ? args[3] : args[4]);
                        break;
                    case "!=":
                    case "<>":
                        writer.Write(val1 != val2 ? args[3] : args[4]);
                        break;
                }
            }
            else
            {
                float val1 = float.Parse(args[0].ToString());
                float val2 = float.Parse(args[2].ToString());

                switch (args[1].ToString())
                {
                    case ">":
                        writer.Write(val1 > val2 ? args[3] : args[4]);
                        break;
                    case "=":
                    case "==":
                        writer.Write(val1 == val2 ? args[3] : args[4]);
                        break;
                    case "<":
                        writer.Write(val1 < val2 ? args[3] : args[4]);
                        break;
                    case "<=":
                        writer.Write(val1 <= val2 ? args[3] : args[4]);
                        break;
                    case ">=":
                        writer.Write(val1 >= val2 ? args[3] : args[4]);
                        break;
                    case "!=":
                    case "<>":
                        writer.Write(val1 != val2 ? args[3] : args[4]);
                        break;
                }
            }

And here are some Unit test explaining the usage :

var template = Handlebars.Compile("{{{ifCond test '>' 1 '>1' '<=1' }}}");
var data = new { test = 2 };
var result = template(data);
Assert.AreEqual(">1", result);

data = new { test = 0 };
result = template(data);
Assert.AreEqual("<=1", result);

template = Handlebars.Compile("{{{ifCond test '=' 1 'eq' 'not eq' }}}");
data = new { test = 1 };
result = template(data);
Assert.AreEqual("eq", result);

data = new { test = 0 };
result = template(data);
Assert.AreEqual("not eq", result);

template = Handlebars.Compile("{{{ifCond test '!=' 1 'diff' 'eq' }}}");
data = new { test = 2 };
result = template(data);
Assert.AreEqual("diff", result);

template = Handlebars.Compile("{{{ifCond str '!=' '' 'not empty' 'empty' }}}");
var datastr = new { str = "abc" };
result = template(datastr);
Assert.AreEqual("not empty", result);

template = Handlebars.Compile("{{{ifCond str '==' '' 'empty' 'not empty' }}}");
datastr = new { str = "" };
result = template(datastr);
Assert.AreEqual("empty", result);

Hope it helps, and I also hope for a better implementation, more elegant, my solution works but I think it can be done in a more concise way.

Here is a usage example with a Int32 value inside a template:

{{ifCond MycountVariable '>' 1 'more than one' 'one'}}

And here is a usage example with a String value inside a template:

{{ifCond MyStringVariable '!=' '' MyStringVariable 'empty value'}}
Matteo Conta
  • 1,423
  • 13
  • 17
3

I'm using the Handlebars.NET author's way as committed in its unit tests and it works like a charm:

Handlebars.RegisterHelper("ifCond", (writer, options, context, arguments) =>
{
    if (arguments[0] == arguments[1])
    {
        options.Template(writer, (object)context);
    }
    else
    {
        options.Inverse(writer, (object)context);
    }
});

(at least in Handlebars.NET 1.10.1).

Dejan
  • 9,150
  • 8
  • 69
  • 117
1

Logic like you're trying to do has to be in a helper function. You can't put relational operators like that directly into a handlebars template. It is designed that way on purpose. Helpers are very easy to create and use. See http://handlebarsjs.com/#helpers more more info.

hbs.registerHelper("IsSame", function(ProdType) {
 if(ProdType == "BlaBlaBla") {
   $('#HereText').append('<p>This is a test</p>');
    }
});

Do this in the template

<div class="row">
   {{IsSame Product.ProdType}}
</div>

so here you are passing your value to a helper function and doing your comparison..

Prasanth Jaya
  • 4,407
  • 2
  • 23
  • 33
  • @Yargicx hey, author of Handlebars.Net here... Prasanth is correct, even though s/he used a Javascript example to explain. Handlebars.Net is an exact (or, as exact as we can get it) port of handlebarsjs, so the behavior is the same in both. Handlebars has no concept of operators in templates; only HelperExpressions and arguments. You can create a helper and pass any number of arguments to it to produce your desired effect. – Rex M Feb 14 '16 at 16:00
  • @Rex M, While I understand handlebars is intended to be "logicless", I don't understand why the #if helper doesn't support simple comparisons out of the box. It's a real pain to dig into the details of it's implementation to make it work. Also, it doesn't have any facilities for debugging. One big gotcha is that your templates are rendered useless (NPI) if the JSON isn't deserialized properly (i.e. it evaluates it as strings instead of objects. – ATL_DEV Oct 29 '21 at 18:51
  • @ATL_DEV here is a good explanation (from 2012): https://github.com/handlebars-lang/handlebars.js/issues/206#issuecomment-4698519 – Rex M Oct 30 '21 at 12:28
1

I tried @Matteo Conta's solution, but it does not support variables combine with text. So I tweaked it a bit for easier to use & better support variables.

Syntax

{{#ifCond arg1 condition arg2}}
       True clause {{variable}}
{{else}}
       False clause {{variable}}
{{/ifCond}}

Code

Handlebars.RegisterHelper("ifCond", (writer, options, context, args) => {
    if (args.Length != 3)
    {
        writer.Write("ifCond:Wrong number of arguments");
        return;
    }
    if (args[0] == null || args[0].GetType().Name == "UndefinedBindingResult")
    {
        writer.Write("ifCond:args[0] undefined");
        return;
    }
    if (args[1] == null || args[1].GetType().Name == "UndefinedBindingResult")
    {
        writer.Write("ifCond:args[1] undefined");
        return;
    }
    if (args[2] == null || args[2].GetType().Name == "UndefinedBindingResult")
    {
        writer.Write("ifCond:args[2] undefined");
        return;
    }
    if (args[0].GetType().Name == "String")
    {
        var val1 = args[0].ToString();
        var val2 = args[2].ToString();

        switch (args[1].ToString())
        {
            case ">":
                if (val1.Length > val2.Length)
                {
                    options.Template(writer, (object)context);
                }
                else
                {
                    options.Inverse(writer, (object)context);
                }
                break;
            case "=":
            case "==":
                if (val1 == val2)
                {
                    options.Template(writer, (object)context);
                }
                else
                {
                    options.Inverse(writer, (object)context);
                }
                break;
            case "<":
                if (val1.Length < val2.Length)
                {
                    options.Template(writer, (object)context);
                }
                else
                {
                    options.Inverse(writer, (object)context);
                }
                break;
            case "!=":
            case "<>":
                if (val1 != val2)
                {
                    options.Template(writer, (object)context);
                }
                else
                {
                    options.Inverse(writer, (object)context);
                }
                break;
        }
    }
    else
    {
        var val1 = float.Parse(args[0].ToString());
        var val2 = float.Parse(args[2].ToString());

        switch (args[1].ToString())
        {
            case ">":
                if (val1 > val2)
                {
                    options.Template(writer, (object)context);
                }
                else
                {
                    options.Inverse(writer, (object)context);
                }
                break;
            case "=":
            case "==":
                if (val1 == val2)
                {
                    options.Template(writer, (object)context);
                }
                else
                {
                    options.Inverse(writer, (object)context);
                }
                break;
            case "<":
                if (val1 < val2)
                {
                    options.Template(writer, (object)context);
                }
                else
                {
                    options.Inverse(writer, (object)context);
                }
                break;
            case "!=":
            case "<>":
                if (val1 != val2)
                {
                    options.Template(writer, (object)context);
                }
                else
                {
                    options.Inverse(writer, (object)context);
                }
                break;
        }
    }
});

Sample usages

var template = Handlebars.Compile(@"{{#ifCond arg1 '>' arg2}}{{arg1}} is greater than {{arg2}}{{else}}{{arg1}} is less than {{arg2}}{{/ifCond}}");
var data = new { arg1 = 2 , arg2 = 1};
var result = template(data);
Assert.Equal("2 is greater than 1", result);

data = new { arg1 = 1, arg2 = 2 };
result = template(data);
Assert.Equal("1 is less than 2", result);

template = Handlebars.Compile(@"{{#ifCond arg1 '<' arg2}}{{arg1}} is less than {{arg2}}{{else}}{{arg1}} is greater than {{arg2}}{{/ifCond}}");
data = new { arg1 = 2, arg2 = 1 };
result = template(data);
Assert.Equal("2 is greater than 1", result);

data = new { arg1 = 1, arg2 = 2 };
result = template(data);
Assert.Equal("1 is less than 2", result);

template = Handlebars.Compile(@"{{#ifCond arg1 '=' arg2}}{{arg1}} is eq to {{arg2}}{{else}}{{arg1}} is not eq to {{arg2}}{{/ifCond}}");
data = new { arg1 = 1, arg2 = 1 };
result = template(data);
Assert.Equal("1 is eq to 1", result);

data = new { arg1 = 2, arg2 = 1 };
result = template(data);
Assert.Equal("2 is not eq to 1", result);

template = Handlebars.Compile(@"{{#ifCond arg1 '!=' arg2}}{{arg1}} is not eq to {{arg2}}{{else}}{{arg1}} is eq to {{arg2}}{{/ifCond}}");
data = new { arg1 = 2, arg2 = 1 };
result = template(data);
Assert.Equal("2 is not eq to 1", result);

template = Handlebars.Compile(@"{{#ifCond str '!=' ''}}not empty{{else}}empty{{/ifCond}}");
var datastr = new { str = "abc" };
result = template(datastr);
Assert.Equal("not empty", result);

template = Handlebars.Compile(@"{{#ifCond str '==' ''}}empty{{else}}not empty{{/ifCond}}");
datastr = new { str = "" };
result = template(datastr);
Assert.Equal("empty", result);
Hung Quach
  • 2,079
  • 2
  • 17
  • 28