samskivert / jmustache

A Java implementation of the Mustache templating language.
Other
834 stars 128 forks source link

Empty lists are not treated as false values for optional sections #110

Closed mohanraj-r closed 5 years ago

mohanraj-r commented 5 years ago

Thanks for this library - works great and is very usable (coming here after handlebars.java and mustache.java libs).

One thing I couldn't get to work is to hide optional sections when the underlying list is empty. I had to add code to make the list to be null to get the section to be hidden. Would be great if empty lists could also be treated as false values and counted towards hiding optional sections.

mohanraj-r commented 5 years ago

Also found the same for a case for an Object that was assigned empty string "". Had to assign it null to get the section to hide.

samskivert commented 5 years ago

Can you provide an example of the first problem? A section that resolves to an empty list should not be rendered. This unit test passes, for example:

    @Test public void testEmptyListSection () {
        test("", "{{#foo}}{{bar}}{{/foo}}", context("foo", Collections.emptyList()));
    }

The foo section is never rendered.

The second problem can be fixed, I think, by calling Mustache.compiler().emptyStringIsFalse(true).

mohanraj-r commented 5 years ago

Thanks @samskivert

What I have is something along the lines of

{{#foo}}
        * Foo    : {{foo}}
 {{/foo}}

In which case the line * Foo : gets displayed even when list foo is empty. Another related question is that when foo is not empty the line * Foo : gets repeated for each item in the list - but I just want to display all elements of the list on the same line just once. How can I do this?

For the string good to know there is an option. But shouldn't empty string be considered as false by default? I think that is the behavior of other templating libs.

samskivert commented 5 years ago

There must be something strange with your data model. If foo is an empty list, then the {{#foo}} section should be rendered zero times, not one. So check that your empty list isn't actually a list that contains a single empty value?

As for displaying all of the values in your list on one line, I'm not sure what a great way to do that is. Mustache is designed to render lists by rendering individual sections repeatedly. So you'll need some sort of outer section that contains an inner repeating section that operates on the list.

As for the defaults. I'm happy with them and not planning to change them. People can read the documentation and make things work the way they want. JMustache has been around for almost 10 years and you're the first person to ask to change that default, so I think it's OK.

mohanraj-r commented 5 years ago

thanks for the clarifications @samskivert i will look closely at my list

mohanraj-r commented 5 years ago

So check that your empty list isn't actually a list that contains a single empty value?

I did check and the list is empty - the workaround I have currently is to collapse the list to a string

private final String foo;  
final List<String> bar = ... ;
foo = bar.size() > 0 ? String.join(", ", bar) : null;

If I replace foo = bar.size() > 0 ? String.join(", ", bar) : null; with foo = bar.size() > 0 ? String.join(", ", bar) : String.valueOf(bar);

I see the output rendered as Foo: [] where [] corresponds to the String.valueOf(bar) and bar is empty. So we know bar is empty. Previously I was trying to use the List<String> bar directly in template and it was getting rendered even when bar is empty.