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

旧城冷巷雨未停 提交于 2019-11-26 22:35:27

问题


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

red, green, blue

Creating a list with the trailing comma is straightforward, given the structure

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

and the template

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

this will resolve to

red, green, blue,

However I cannot see an elegant way of expressing the case without the trailing comma. I can always generate the list in code before passing it into the template, but I was wondering whether the library offers an alternative approach such as allowing you to to detect whether it is the last item in a list within the template.


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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

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



回答5:


I can't think of many situations where you'd want to list an unknown number of items outside of a <ul> or <ol>, but this is how you'd do it:

<p>
    Comma separated list, in sentence form;
    {{#each test}}{{#if @index}}, {{/if}}{{.}}{{/each}};
    sentence continued.
</p>

…will produce:

Command separated list, in sentence form; asdf1, asdf2, asdf3; sentence continued.

This is Handlebars, mind you. @index will work if test is an Array.




回答6:


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.




回答7:


There is not a built-in way to do this in Mustache. You have to alter your model to support it.

One way to implement this in the template is to use the inverted selection hat {{^last}} {{/last}} tag. It will only omit text for the last item in the list.

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

Or you can add a delimiter string as ", " to the object, or ideally the base class if you're using a language that has inheritance, then set "delimiter" to an empty string " " for the last element like this:

{{#items}}
    {{name}}{{delimiter}}
{{/items}}



回答8:


As the question is:

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

Then changing the data - when being the last item is already implicit by it being the final item in the array - isn't elegant.

Any mustache templating language that has array indices can do this properly,. ie. without adding anything to the data. This includes handlebars, ractive.js, and other popular mustache implementations.

{{# names:index}}
    {{ . }}{{ #if index < names.length - 1 }}, {{ /if }}
{{ / }}



回答9:


For JSON data I suggest:

Mustache.render(template, settings).replace(/,(?=\s*[}\]])/mig,'');

The regexp will remove any , left hanging after the last properties.

This will also remove , from string values contining ", }" or ", ]" so make sure you know what data will be put into your JSON




回答10:


As Mustache stands on Handlebars, why not use a @data variable? I found this the cleanest option:

{{#if @last}}, {{/if}}

More info: http://handlebarsjs.com/reference.html#data




回答11:


Simplest way I found was to render list and then remove last char.

  1. Render mustache.
  2. Remove any white space before and after string.
  3. Then remove last character

    let renderedData = Mustache Render(dataToRender, data); renderedData=(renderedData.trim()).substring(0, renderedData.length-1)




回答12:


Interesting. I know it's kind of lazy but I usually get around this by templating in the value assignment rather than trying to comma delimitate the values.

var global.items = {};
{{#items}}
    global.items.{{item_name}} = {{item_value}};
{{/items}}



回答13:


I tend to think this is a task well suited to CSS (as answered by others). However, assuming you are attempting to do something like produce a CSV file, you would not have HTML and CSS available to you. Also, if you are considering modifying data to do this anyway, this may be a tidier way to do it:

var data = {
  "items": [
    {"name": "red"},
    {"name": "green"},
    {"name": "blue"}
  ]
};

// clone the original data. 
// Not strictly necessary, but sometimes its
// useful to preserve the original object
var model = JSON.parse(JSON.stringify(data));

// extract the values into an array and join 
// the array with commas as the delimiter
model.items = Object.values(model.items).join(',');

var html = Mustache.render("{{items}}", model);



回答14:


If you are using java, you can use the following :

https://github.com/spullara/mustache.java/blob/master/compiler/src/test/java/com/github/mustachejava/util/DecoratedCollectionTest.java

MustacheFactory mf = new DefaultMustacheFactory();
Mustache test = mf.compile(new StringReader("{{#test}}{{#first}}[{{/first}}{{^first}}, {{/first}}\"{{value}}\"{{#last}}]{{/last}}{{/test}}"), "test");
StringWriter sw = new StringWriter();
test.execute(sw, new Object() {
    Collection test = new DecoratedCollection(Arrays.asList("one", "two", "three"));
}).flush();
System.out.println(sw.toString());


来源:https://stackoverflow.com/questions/6114435/in-mustache-templating-is-there-an-elegant-way-of-expressing-a-comma-separated-l

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!