In Mustache templating is there an elegant way of expressing a comma separated list without the trailing comma?

后端 未结 17 1540
滥情空心
滥情空心 2020-12-02 10:26

I am using the Mustache templating library and trying to generate a comma separated list without a trailing comma, e.g.

red, green, blue

相关标签:
17条回答
  • 2020-12-02 10:41

    Hrm, doubtful, the mustache demo pretty much shows you, with the first property, that you have to have the logic inside the JSON data to figure out when to put the comma.

    So your data would look something like:

    {
      "items": [
        {"name": "red", "comma": true},
        {"name": "green", "comma": true},
        {"name": "blue"}
      ]
    }
    

    and your template

    {{#items}}
        {{name}}{{#comma}},{{/comma}}
    {{/items}}
    

    I know it's not elegant, but as mentioned by others Mustache is very lightweight and does not provide such features.

    0 讨论(0)
  • 2020-12-02 10:41

    Cheat and use CSS.

    If your model is:

    {
      "items": [
        {"name": "red"},
        {"name": "green"},
        {"name": "blue"}
      ]
    }
    

    then make your template

    <div id="someContainer">
    {{#items}}
        <span>{{name}}<span>
    {{/items}}
    </div>
    

    and add a little bit of CSS

    #someContainer span:not(:last-of-type)::after {
      content: ", "    
    }
    

    I'm guessing someone will say that this is a bad case of putting markup in the presentation but I don't think it is. Comma separating values is a presentation decision to make interpreting the underlying data easier. It's similar to alternating the font color on entries.

    0 讨论(0)
  • 2020-12-02 10:42

    I think a better way is to change the model dynamically. For example, if you are using JavaScript:

    model['items'][ model['items'].length - 1 ].last = true;
    

    and in your template, use inverted section:

    {{#items}}
        {{name}}{{^last}}, {{/last}}
    {{/items}}
    

    to render that comma.

    0 讨论(0)
  • 2020-12-02 10:42

    The question of whether Mustache offers an elegant way to do this has been answered, but it occurred to me that the most elegant way to do this may be to use CSS rather than changing the model.

    Template:

    <ul class="csl">{{#items}}<li>{{name}}</li>{{/items}}</ul>
    

    CSS:

    .csl li
    {
        display: inline;
    }
    .csl li:before
    {
        content: ", "
    }
    .csl li:first-child:before
    {
        content: ""
    }
    

    This works in IE8+ and other modern browsers.

    0 讨论(0)
  • 2020-12-02 10:45

    If you happen to be using jmustache, you can use the special -first or -last variables:

    {{#items}}{{name}}{{^-last}}, {{/-last}}{{/items}}
    
    0 讨论(0)
  • 2020-12-02 10:45

    I know this is an old question, but I still wanted to add an answer that provides another approach.

    Main answer

    Mustache supports lambdas, (see documentation) so one can write it this way:

    Template:

        {{#removeTrailingComma}}{{#items}}{{name}}, {{/items}}{{/removeTrailingComma}}
    

    Hash:

        {
          "items": [
            {"name": "red"},
            {"name": "green"},
            {"name": "blue"}
          ]
          "removeTrailingComma": function() {
            return function(text, render) {
              var original = render(text);
              return original.substring(0, original.length - 2);
            }
          }
        }
    

    Output:

    red, green, blue

    Comment

    Personally, I like this approach over the others, since IMHO the model should only specify what is rendered and not how it is rendered. Technically, the lambda is part of the model, but the intent is much more clear.

    I use this approach for writing my own OpenApi generators. There, Mustache is wrapped by Java, but the functionality is pretty much the same. This is what creating lambdas looks like for me: (in Kotlin)

        override fun addMustacheLambdas(): ImmutableMap.Builder<String, Mustache.Lambda> =
            super.addMustacheLambdas()
                .put("lowerCase", Mustache.Lambda { fragment, writer ->
                    writer.write(fragment.execute().toLowerCase())
                })
                .put("removeLastComma", Mustache.Lambda { fragment, writer ->
                    writer.write(fragment.execute().removeSuffix(","))
                })
                .put("printContext", Mustache.Lambda { fragment, writer ->
                    val context = fragment.context()
                    println(context) // very useful for debugging if you are not the author of the model
                    writer.write(fragment.execute())
                })
    
    0 讨论(0)
提交回复
热议问题