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


83

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

빨강, 녹색, 파랑

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

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

및 템플릿

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

이것은 해결 될 것이다

빨강, 녹색, 파랑,

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


코드에 쉼표로 구분 된 목록을 작성하고 단일 문자열로 콧수염에 전달하는 것이 좋습니다. 선택 사항 및 간단한 목록보다 더 복잡한 논리는 거의 항상 고전적인 프로그래밍 언어에서 더 읽기 쉽습니다.
yeoman

콧수염보다 더 복잡한 템플릿 엔진은이 작업을 아주 쉽게 수행 할 수 있습니다. 그러나 그들 중 어느 누구도 읽을 수는 없습니다. 그리고 이것을 염두에두고 콧수염을 단순하게 만들기로 결정한 것은 매우 신중한 결정이었습니다. : D
yeoman

답변:


43

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

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

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

및 귀하의 템플릿

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

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


24
데이터 형식을 지정할 수도 있습니다. "items": [ "red", "green", "blue"] 다음 {{items}}을 수행하면 이미 쉼표로 구분 된 목록이 출력됩니다. :)
Anthony Chua

10
댓글은 실제로 정답이어야합니다. 훨씬 더 깨끗합니다. 소비자의 시각적 요구를 충족시키기 위해 데이터 소스를 수정하는 것은 정말 나쁜 형태입니다.
Slick86

@AnthonyChua 우아하지만, 이것은 (a) 문서화되지 않은 동작이므로 향후 변경 될 가능성은 없지만 (b) 쉼표 뒤에 공백을 넣지 않으므로 first,second,third.
caw

8
마지막 항목에 하나의 속성 만 추가하는 것이 더 적습니다. {"name": "blue", "last": 1} 다음 거꾸로 섹션 사용{{#items}} {{name}}{{^last}}, {{/last}} {{/items}}
TmTron

1
@ slick86 위의 주석은 쉼표로 구분 된 목록을 생성하지만 각 항목이 큰 따옴표로 묶여있는 목록은 아닙니다.
GlenRSmith

92

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

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

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

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

쉼표를 렌더링합니다.


2
나는 그것을 좋아한다. Mustache가 기능이 충분하지 않다고 생각할 때마다 템플릿이 모든 것을 수행하는 '오래된'방식이라고 생각하기 때문입니다. 글쎄요, 저는 JSP에서 왔습니다.
Nicolas Zozol 2013

1
@NicolasZozol 콧수염이 정확히 이런 종류의 단순함을 염두에두고 만들어 졌다는 것을 알고 있습니까? : D
유사시

@NicolasZozol 정말 복잡한 경우에는 프로그래밍 언어로 직접 문자열을 작성하여 템플릿 언어가 처리 할 수있는 간단한보기 모델을 만드는 것이 가장 좋습니다. 이 경우 쉼표로 구분 된 목록은 코드를 통해 하나의 단일 문자열로 제공됩니다.
여만

41

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: ", "    
}

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


이것은 당신이 다른 방법 사용 할 수 있습니다, 오래된 브라우저를 지원해야하므로 경우에만 IE9 +에서 호환 주목해야한다
PoeHaH

1
이것은 콧수염이 웹 페이지에 사용되고 있다는 가정을합니다.-그것 이외에도 많은 용도가 있습니다
tddmonkey

30

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

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

4
OP가 JavaScript Mustache 라이브러리를 참조하고 있다는 것을 알고 있지만이 페이지를 찾는 다른 jmustache 사용자 (나와 같은)에게 도움이 될 수 있습니다.
dbort

답변 해 주셔서 감사합니다. SpringBoot로 템플릿을 렌더링하는데도 사용했습니다. 모델을 변경할 필요가 없습니다. 이 기능을 정말로 찾고있었습니다. 평등 컨트롤 (예를 들어이있는 경우 나 또한 궁금해 {{#something=TEXT}})
장 발장

8

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

이것은 핸들 바입니다. @indextest배열 이면 작동합니다 .


꽤 우아한 것 같습니다! #if 및 @index가 콧수염의 모든 또는 대부분의 구현에서 사용 가능하다고 가정합니다 ... 대부분의 콧수염 사용자는 HTML이 가장 일반적인 사용 사례 인 경우에도 HTML을 생성하지 않습니다.
Spike0xff

이것은 멋진 솔루션이며 매력처럼 작동합니다. 이 답변을 접하는 모든 사람을 위해 결과를 HTML 태그로 래핑하려면 {{.}}.
NetOperator Wibby

이것은 올바른 포인터였습니다. 이제 더 나은 제어를 위해 [first] 및 [last] 조건문을 사용할 수도 있습니다. stackoverflow.com/questions/11479094/…
Maksym

6

콧수염이이를위한 우아한 방법을 제공하는지에 대한 질문에 대한 답을 얻었지만이를 수행하는 가장 우아한 방법은 모델을 변경하는 대신 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 + 및 기타 최신 브라우저에서 작동합니다.


5

Mustache에서는이를 수행하는 기본 제공 방법이 없습니다. 이를 지원하려면 모델을 변경해야합니다.

템플릿에서이를 구현하는 한 가지 방법은 반전 된 선택 모자 {{^last}} {{/last}}태그 를 사용하는 것 입니다. 목록 의 마지막 항목에 대한 텍스트 만 생략 됩니다.

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

또는 ", "개체에 구분자 문자열을 추가 하거나 상속이있는 언어를 사용하는 경우 기본 클래스를 추가 한 다음 다음 " "과 같이 마지막 요소에 대해 "delimiter"를 빈 문자열로 설정할 수 있습니다 .

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

1
명확하게 말하면, 입력 데이터의 어떤 내용이 실제로 작동하려면 "last"라는 이름이 지정되어야합니다. 옳은?
FrustratedWithFormsDesigner

1
맞습니다 last. 라는 부울 속성을 추가하여 모델을 변경해야합니다 . 그런 다음 컬렉션의 마지막 항목을로 설정합니다 last=true.
cosbor11

1
이 경우 "모델"은 실제로 사용자가 편집 할 수있는 구성 파일입니다. 목록의 올바른 항목에 "마지막"을 올바로 배치하는 것을 신뢰하고 싶지는 않습니다.
FrustratedWithFormsDesigner

템플릿 엔진을 호출하는 데 어떤 언어를 사용하고 있습니까?
cosbor11

2
이 경우 런타임 중에 config파일 표현을 python 객체로 변환하십시오 . 구성이 json또는에 있다고 생각하고 xml있습니까? 그런 다음 템플릿 엔진에 전달하기 전에 컬렉션의 마지막 항목을 가져 와서 last속성을 적용합니다 .
cosbor11

3

JSON 데이터의 경우 다음을 제안합니다.

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

정규 표현식은 ,마지막 속성 이후에 남아있는 모든 중단을 제거합니다 .

,",}"또는 ",]"를 포함하는 문자열 값 에서도 제거 되므로 JSON에 어떤 데이터를 넣을지 확인하십시오.


템플릿 JSON 스키마가 있기 때문에 이것은 확실히 나를 위해 트릭을 수행했습니다. 감사!
yahyazini

2

질문은 다음과 같습니다.

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

그런 다음 데이터 변경-마지막 항목이 이미 배열의 최종 항목이 됨으로써 암시적일 때-우아하지 않습니다.

배열 인덱스가있는 모든 콧수염 템플릿 언어는이 작업을 제대로 수행 할 수 있습니다. 즉. 데이터에 아무것도 추가하지 않고 . 여기에는 핸들 바, ractive.js 및 기타 인기있는 콧수염 구현이 포함됩니다.

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

1
확인. 그러나 콧수염이없는if
mauron85

@ mauron85 맞습니다. 나는 (그리고 다른 많은) 콧수염을 원래 콧수염에서 영감을받은 다양한 템플릿 언어에 복수형으로 사용합니다.
mikemaccana

1

내가 찾은 가장 간단한 방법은 목록을 렌더링 한 다음 마지막 문자를 제거하는 것입니다.

  1. 콧수염을 렌더링합니다.
  2. 문자열 앞뒤의 공백을 제거하십시오.
  3. 그런 다음 마지막 문자 제거

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



0

흥미 롭군. 나는 그것이 게으르다는 것을 알고 있지만 일반적으로 값을 쉼표로 구분하는 대신 값 할당에서 템플릿을 작성하여이 문제를 해결합니다.

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

0

나는 이것이 CSS에 잘 맞는 작업이라고 생각하는 경향이 있습니다. 그러나 CSV 파일 생성과 같은 작업을 시도한다고 가정하면 HTML 및 CSS를 사용할 수 없습니다. 또한이 작업을 수행하기 위해 데이터를 수정하려는 경우 다음과 같이 더 깔끔한 방법이 될 수 있습니다.

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

0

Java를 사용하는 경우 다음을 사용할 수 있습니다.

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

0

나는 이것이 오래된 질문이라는 것을 알고 있지만 여전히 다른 접근 방식을 제공하는 답변을 추가하고 싶었습니다.

주요 답변

Mustache는 람다를 지원합니다 ( 문서 참조). ) 다음과 같이 작성할 수 있습니다.

주형:

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

해시시:

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

산출:

빨강, 녹색, 파랑

논평

개인적으로, 나는 다른 사람을 통해이 방법을 좋아한다, 이럴 이후 모델은 지정해야 무엇을 렌더링하지 어떻게 이 렌더링됩니다. 기술적으로 람다는 모델의 일부이지만 의도는 훨씬 더 명확합니다.

이 접근 방식을 사용하여 자체 OpenApi 생성기를 작성합니다. Mustache는 Java로 래핑되어 있지만 기능은 거의 동일합니다. 이것은 람다를 만드는 모습입니다. (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

제 경우에는 동적 SQL 쿼리로 작업 할 때 사용자 지정 함수를 사용하고 있습니다.

    $(document).ready(function () {
    var output = $("#output");    
    var template = $("#test1").html();
    var idx = 0;
    var rows_count = 0;
    var data = {};
    
    data.columns = ["name", "lastname", "email"];
    data.rows  = [
        ["John", "Wick", "john.wick@hotmail.com"],
      ["Donald", "Duck", "donald.duck@ducks.com"],
      ["Anonymous", "Anonymous","jack.kowalski@gmail.com"]
    ];

    data.rows_lines = function() {
        let rows = this.rows;
      let rows_new = [];
      for (let i = 0; i < rows.length; i++) {
        let row = rows[i].map(function(v) {
            return `'${v}'`
        })
                rows_new.push([row.join(",")]);
      }
      rows_count = rows_new.length;
      return rows_new
    }
    data.last = function() {
        return idx++ === rows_count-1; // omit comma for last record
    }
    
    var html = Mustache.render(template, data);
    output.append(html);

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/4.0.1/mustache.min.js"></script>
<h2>Mustache example: Generate SQL query (last item support - omit comma for last insert)</h2>

<div id="output"></div>

<script type="text/html" id="test1">
    INSERT INTO Customers({{{columns}}})<br/>
    VALUES<br/>
        {{#rows_lines}}
                ({{{.}}}){{^last}},{{/last}}<br/>
      {{/rows_lines}}
</script>

https://jsfiddle.net/tmdoit/4p5duw70/8/


0

더 복잡한 시나리오에서는 여러 가지 이유로 뷰 모델이 바람직합니다. 디스플레이 또는이 경우 템플릿 처리에 더 적합한 방식으로 모델의 데이터를 나타냅니다.

보기 모델을 사용하는 경우 목표를 촉진하는 방식으로 목록을 쉽게 나타낼 수 있습니다.

모델:

{
    name: "Richard",
    numbers: [1, 2, 3]
}

모델보기 :

{
    name: "Richard",
    numbers: [
        { first: true, last: false, value: 1 },
        { first: false, last: false, value: 2 },
        { first: false, last: true, value: 3 }
    ]
}

두 번째 목록 표현은 입력하기가 끔찍하지만 코드에서 만드는 것은 매우 간단합니다. 뷰 모델에 모델을 매핑하는 동안, 당신이 필요로하는 모든 목록을 대체 first하고 last이 표현에 대한합니다.

function annotatedList(values) {
    let result = []
    for (let index = 0; index < values.length; ++index) {
        result.push({
            first: index == 0,
            last: index == values.length - 1,
            value: values[index]
        })
    }
    return result
}

제한되지 않은 목록의 경우 , 그 중 하나가 후행 쉼표를 피하는 데 충분하므로 설정 first및 생략 만 가능 last합니다.

사용 first:

{{#numbers}}{{^first}}, {{/first}}{{value}}{{/numbers}}

사용 last:

{{#numbers}}{{value}}{{^last}}, {{/last}}{{/numbers}}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.