developer tip

Mustache 템플릿에서 후행 쉼표없이 쉼표로 구분 된 목록을 표현하는 우아한 방법이 있습니까?

copycodes 2020. 10. 11. 10:46
반응형

Mustache 템플릿에서 후행 쉼표없이 쉼표로 구분 된 목록을 표현하는 우아한 방법이 있습니까?


Mustache 템플릿 라이브러리를 사용하고 있으며 , 예를 들어 후행 쉼표없이 쉼표로 구분 된 목록을 생성하려고합니다.

빨강, 녹색, 파랑

후행 쉼표로 목록을 만드는 것은 구조를 고려할 때 간단합니다.

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

및 템플릿

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

이것은 해결 될 것이다

빨강, 녹색, 파랑,

그러나 후행 쉼표 없이는 케이스를 우아하게 표현할 수 없습니다. 템플릿에 전달하기 전에 항상 코드에서 목록을 생성 할 수 있지만 라이브러리가 템플릿 내 목록의 마지막 항목인지 여부를 감지 할 수 있도록 허용하는 것과 같은 대체 접근 방식을 제공하는지 궁금합니다.


흠, 의심 스럽지만 콧수염 데모first속성 과 함께 쉼표를 넣을 때를 파악하기 위해 JSON 데이터 내부에 논리가 있어야 함을 거의 보여줍니다 .

따라서 데이터는 다음과 같습니다.

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

및 귀하의 템플릿

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

우아하지는 않지만 다른 사람들이 언급했듯이 Mustache는 매우 가볍고 그러한 기능을 제공하지 않습니다.


더 나은 방법은 모델을 동적으로 변경하는 것입니다. 예를 들어 JavaScript를 사용하는 경우 :

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

템플릿에서 반전 섹션을 사용하십시오.

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

쉼표를 렌더링합니다.


CSS를 속이고 사용하십시오.

모델이 다음과 같은 경우 :

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

그런 다음 템플릿을 만드십시오.

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

그리고 약간의 CSS를 추가합니다.

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

나는 누군가가 이것이 프레젠테이션에 마크 업을 넣는 나쁜 경우라고 말할 것이라고 생각하지만 그렇게 생각하지 않습니다. 값을 구분하는 쉼표는 기본 데이터를 더 쉽게 해석하기위한 프레젠테이션 결정입니다. 항목의 글꼴 색상을 번갈아 가며 바꾸는 것과 유사합니다.


사용 될 일 경우 jmustache을 , 당신은 특별한 사용할 수 있습니다 -first또는 -last변수를 :

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

Mustache가이를위한 우아한 방법을 제공하는지 여부에 대한 질문에 대한 답을 얻었지만이를 수행하는 가장 우아한 방법은 모델을 변경하는 대신 CSS를 사용하는 것일 수 있습니다.

주형:

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

CSS :

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

이것은 IE8 + 및 기타 최신 브라우저에서 작동합니다.


<ul>또는 외부에 알 수없는 수의 항목을 나열하고 싶은 상황을 많이 생각할 수 없지만 <ol>다음과 같이 할 수 있습니다.

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

… 생산 :

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

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


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}}

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 }}
{{ / }}

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


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


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)


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}}

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);

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());

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

반응형