Trong khuôn mẫu Mustache có cách nào thanh lịch để thể hiện danh sách được phân tách bằng dấu phẩy mà không có dấu phẩy ở cuối không?


83

Tôi đang sử dụng thư viện tạo mẫu Mustache và cố gắng tạo danh sách được phân tách bằng dấu phẩy mà không có dấu phẩy ở cuối, ví dụ:

đỏ lục lam

Tạo một danh sách với dấu phẩy ở cuối rất đơn giản, dựa trên cấu trúc

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

và mẫu

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

điều này sẽ giải quyết

đỏ lục lam,

Tuy nhiên, tôi không thể thấy một cách thanh lịch để diễn đạt trường hợp mà không có dấu phẩy ở cuối. Tôi luôn có thể tạo danh sách bằng mã trước khi chuyển nó vào mẫu, nhưng tôi đang băn khoăn liệu thư viện có cung cấp cách tiếp cận thay thế như cho phép bạn phát hiện xem đó có phải là mục cuối cùng trong danh sách trong mẫu hay không.


Tôi khuyên bạn nên xây dựng danh sách được phân tách bằng dấu phẩy trong mã của bạn và chuyển nó vào ria mép dưới dạng một chuỗi duy nhất. Logic phức tạp hơn các tùy chọn và danh sách đơn giản hầu như luôn dễ đọc hơn trong các ngôn ngữ lập trình cổ điển.
yeoman

Các công cụ tạo mẫu phức tạp hơn ria mép có thể làm điều này khá dễ dàng. Đó là không phải là rất có thể đọc được trong bất kỳ trong số họ, tuy nhiên, và với điều này trong tâm trí, quyết định để làm cho bộ ria mép đơn giản như nó là khá cân nhắc: D
yeoman

Câu trả lời:


43

Hrm, nghi ngờ, bản demo ria mép cho bạn thấy khá nhiều, với thuộc firsttính, rằng bạn phải có logic bên trong dữ liệu JSON để tìm ra thời điểm đặt dấu phẩy.

Vì vậy, dữ liệu của bạn sẽ trông giống như sau:

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

và mẫu của bạn

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

Tôi biết nó không thanh lịch, nhưng như những người khác đã đề cập, Mustache rất nhẹ và không cung cấp các tính năng như vậy.


24
bạn cũng có thể định dạng dữ liệu của mình, để "items": ["red", "green", "blue"] thì bạn chỉ cần thực hiện {{items}} là sẽ xuất ra danh sách được phân tách bằng dấu phẩy rồi :)
Anthony Chua

10
Nhận xét thực sự phải là câu trả lời chính xác. Sạch hơn nhiều. Hình thức thực sự tồi tệ khi sửa đổi nguồn dữ liệu của bạn để phục vụ nhu cầu thị giác của người tiêu dùng
Slick86

@AnthonyChua Mặc dù thanh lịch, nhưng điều này có thể (a) không được ghi lại hành vi và do đó có thể thay đổi trong tương lai, mặc dù khó xảy ra, và (b) điều này không đặt dấu cách sau dấu phẩy, vì vậy bạn sẽ có một cái gì đó như thế first,second,third.
caw

8
nó ít việc phải chỉ có thêm một tài sản cho mục cuối cùng {"name": "blue", "last": 1}và sau đó sử dụng một phần đảo ngược{{#items}} {{name}}{{^last}}, {{/last}} {{/items}}
TmTron

1
@ slick86 Nhận xét ở trên của bạn dẫn đến một danh sách được phân tách bằng dấu phẩy, nhưng không phải là một danh sách trong đó mỗi mục được đặt trong dấu ngoặc kép.
GlenRSmith

92

Tôi nghĩ một cách tốt hơn là thay đổi mô hình một cách linh động. Ví dụ: nếu bạn đang sử dụng JavaScript:

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

và trong mẫu của bạn, hãy sử dụng phần đảo ngược:

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

để hiển thị dấu phẩy đó.


2
Tôi thích nó. Mỗi lần tôi nghĩ Mustache không có đủ tính năng, đó là bởi vì tôi nghĩ cách 'cũ' nơi mẫu thực hiện mọi thứ - tốt, tôi đến từ JSP.
Nicolas Zozol

1
@NicolasZozol Bạn có nhận ra rằng ria mép được tạo ra với sự đơn giản như vậy không? : D
yeoman

@NicolasZozol Đối với những trường hợp thực sự phức tạp, tốt nhất bạn nên xây dựng chuỗi trực tiếp bằng ngôn ngữ lập trình và do đó tạo mô hình dạng xem đơn giản mà ngôn ngữ mẫu có thể xử lý. Trong trường hợp này, danh sách được phân tách bằng dấu phẩy sẽ được cung cấp qua mã dưới dạng một chuỗi duy nhất.
yeoman

41

Gian lận và sử dụng CSS.

Nếu mô hình của bạn là:

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

sau đó tạo mẫu của bạn

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

và thêm một chút CSS

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

Tôi đoán ai đó sẽ nói rằng đây là một trường hợp tồi tệ khi đưa đánh dấu vào bài thuyết trình nhưng tôi không nghĩ là như vậy. Dấu phẩy phân tách các giá trị là một quyết định trình bày để làm cho việc giải thích dữ liệu cơ bản dễ dàng hơn. Nó tương tự như xen kẽ màu chữ trên các mục nhập.


Cần lưu ý đây là tương thích trong IE9 chỉ +, vì vậy nếu bạn cần hỗ trợ trình duyệt cũ, bạn có thể phải sử dụng phương pháp khác
PoeHaH

1
Điều này làm cho các giả định rằng bộ ria mép đang được sử dụng ở các web-trang - nó có rất nhiều công dụng ngoài điều đó quá
tddmonkey

30

Nếu bạn tình cờ sử dụng jmustache , bạn có thể sử dụng các biến đặc biệt -firsthoặc -last:

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

4
Tôi nhận ra rằng OP đang đề cập đến thư viện JavaScript Mustache, nhưng điều này có thể giúp những người dùng jmustache khác (như tôi) tìm thấy trang này.
dbort

Cảm ơn rất nhiều cho câu trả lời. Tôi cũng đã sử dụng điều này để hiển thị một mẫu với SpringBoot. Không cần thay đổi mô hình. Tôi thực sự đang tìm kiếm tính năng này. Tôi cũng tự hỏi liệu có kiểm soát bình đẳng (ví dụ {{#something=TEXT}})
JeanValjean

8

Tôi không thể nghĩ ra nhiều trường hợp mà bạn muốn liệt kê một số lượng không xác định các mục bên ngoài <ul>hoặc <ol>, nhưng đây là cách bạn thực hiện:

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

…sẽ sản xuất:

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

Đây là Handlebars, phiền bạn. @indexsẽ hoạt động nếu testlà một Mảng.


có vẻ khá tao nhã! giả sử #if và @index có sẵn trong tất cả hoặc hầu hết các triển khai của ria mép ... Hãy nhớ rằng, nhiều người dùng ria mép trong chúng ta không tạo HTML, ngay cả khi đó là trường hợp sử dụng phổ biến nhất.
Spike0xff

Đây là một giải pháp tuyệt vời, hoạt động như một sự quyến rũ. Lưu ý cho bất kỳ ai bắt gặp câu trả lời này, nếu bạn muốn gói kết quả trong thẻ HTML, hãy làm như vậy xung quanh {{.}}.
NetOperator Wibby

Đây là con trỏ đúng. Có vẻ như bây giờ bạn cũng có thể sử dụng các điều kiện [đầu tiên] và [cuối cùng] để kiểm soát tốt hơn. stackoverflow.com/questions/11479094/…
Maksym

6

Câu hỏi về việc liệu Mustache có cung cấp một cách thanh lịch để thực hiện điều này hay không đã được giải đáp, nhưng tôi nhận ra rằng cách tốt nhất để làm điều này có thể là sử dụng CSS thay vì thay đổi mô hình.

Bản mẫu:

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

CSS:

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

Điều này hoạt động trong IE8 + và các trình duyệt hiện đại khác.


5

Không có một cách tích hợp nào để thực hiện việc này trong Mustache. Bạn phải thay đổi mô hình của mình để hỗ trợ nó.

Một cách để triển khai điều này trong mẫu là sử dụng {{^last}} {{/last}}thẻ mũ lựa chọn đảo ngược . Nó sẽ chỉ bỏ qua văn bản cho mục cuối cùng trong danh sách.

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

Hoặc bạn có thể thêm một chuỗi dấu phân cách ", "vào đối tượng hoặc lý tưởng là lớp cơ sở nếu bạn đang sử dụng ngôn ngữ có tính kế thừa, sau đó đặt "dấu phân tách" thành một chuỗi trống " "cho phần tử cuối cùng như sau:

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

1
Chỉ cần rõ ràng, một cái gì đó trong dữ liệu đầu vào sẽ thực sự cần được đặt tên là "cuối cùng" để điều này hoạt động. Chính xác?
FrustratedWithFormsDesigner

1
Đúng, bạn sẽ phải thay đổi mô hình của mình bằng cách thêm thuộc tính boolean được gọi last. Sau đó đặt mục cuối cùng trong bộ sưu tập thành last=true.
cosbor11

1
"Mô hình" trong trường hợp này thực sự là một tệp cấu hình mà người dùng có thể chỉnh sửa ... Tôi không nghĩ rằng tôi muốn tin tưởng họ đặt đúng "cuối cùng" vào đúng mục trong danh sách.
FrustratedWithFormsDesigner

bạn đang sử dụng ngôn ngữ nào để gọi công cụ mẫu?
cosbor11

2
Trong trường hợp đó trong thời gian chạy, hãy chuyển đổi configbiểu diễn tệp thành một đối tượng python. Tôi đoán cấu hình nằm trong jsonhoặc xml, phải không? Sau đó, trước khi bạn chuyển nó đến công cụ mẫu, hãy lấy mục cuối cùng của bộ sưu tập và áp dụng thuộc lasttính.
cosbor11

3

Đối với dữ liệu JSON, tôi đề xuất:

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

Regexp sẽ loại bỏ bất kỳ phần ,treo bên trái nào sau các thuộc tính cuối cùng.

Thao tác này cũng sẽ xóa ,khỏi các giá trị chuỗi liên kết ",}" hoặc ",]", vì vậy hãy đảm bảo bạn biết dữ liệu nào sẽ được đưa vào JSON của mình


Điều này chắc chắn là một mẹo nhỏ đối với tôi vì tôi có một lược đồ JSON được tạo mẫu. Cảm ơn!
yahyazini

2

Như câu hỏi là:

Có cách nào thanh lịch để thể hiện danh sách được phân tách bằng dấu phẩy mà không có dấu phẩy ở cuối không?

Sau đó, việc thay đổi dữ liệu - khi là mục cuối cùng đã được ngầm hiểu bởi nó là mục cuối cùng trong mảng - là không tốt.

Bất kỳ ngôn ngữ tạo mẫu ria mép nào có chỉ số mảng đều có thể thực hiện điều này đúng cách ,. I E. mà không cần thêm bất cứ thứ gì vào dữ liệu . Điều này bao gồm thanh điều khiển, ractive.js và các triển khai ria mép phổ biến khác.

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

1
Đồng ý. Nhưng ria mép không cóif
mauron85

@ mauron85 Thật vậy. Tôi (và nhiều người khác) sử dụng ria mép như một số nhiều cho các ngôn ngữ tạo mẫu khác nhau lấy cảm hứng từ bộ ria mép nguyên bản.
mikemaccana

1

Cách đơn giản nhất mà tôi tìm thấy là hiển thị danh sách và sau đó xóa ký tự cuối cùng.

  1. Render ria mép.
  2. Xóa bất kỳ khoảng trắng nào trước và sau chuỗi.
  3. Sau đó xóa ký tự cuối cùng

    let renderData = Mustache Render (dataToRender, dữ liệu); renderData = (renderData.trim ()). substring (0, renderData.length-1)


1

Trong trường hợp sử dụng Handlebars là một tùy chọn, giúp mở rộng khả năng của Mustache, bạn có thể sử dụng biến @data:

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

Thông tin thêm: http://handlebarsjs.com/reference.html#data


3
Tay lái được xây dựng trên đầu trang của Moustache, không phải là cách khác xung quanh
Andy Jones

0

Hấp dẫn. Tôi biết đó là loại lười biếng nhưng tôi thường giải quyết vấn đề này bằng cách tạo khuôn mẫu trong việc gán giá trị thay vì cố gắng phân định các giá trị bằng dấu phẩy.

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

0

Tôi có xu hướng nghĩ rằng đây là một nhiệm vụ rất phù hợp với CSS (như những người khác đã trả lời). Tuy nhiên, giả sử bạn đang cố gắng làm điều gì đó như tạo tệp CSV, bạn sẽ không có sẵn HTML và CSS. Ngoài ra, nếu bạn đang xem xét việc sửa đổi dữ liệu để thực hiện việc này, thì đây có thể là cách gọn gàng hơn để thực hiện:

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

Nếu bạn đang sử dụng java, bạn có thể sử dụng như sau:

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

Tôi biết đây là một câu hỏi cũ, nhưng tôi vẫn muốn thêm một câu trả lời cung cấp một cách tiếp cận khác.

Câu trả lời chính

Mustache hỗ trợ lambdas, ( xem tài liệu ) nên người ta có thể viết nó theo cách này:

Bản mẫu:

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

Băm:

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

Đầu ra:

đỏ lục lam

Bình luận

Cá nhân tôi thích cách tiếp cận này hơn các cách khác, vì IMHO mô hình chỉ nên chỉ định những gì được hiển thị chứ không phải cách nó được hiển thị. Về mặt kỹ thuật, lambda là một phần của mô hình, nhưng mục đích rõ ràng hơn nhiều.

Tôi sử dụng phương pháp này để viết các trình tạo OpenApi của riêng mình. Ở đó, Mustache được bao bọc bởi Java, nhưng chức năng thì khá giống nhau. Đây là những gì tạo lambdas trông như thế nào đối với tôi: (trong 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

Tôi đang sử dụng các hàm tùy chỉnh cho điều đó, trong trường hợp của tôi khi làm việc với các truy vấn SQL động.

    $(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

Trong các tình huống phức tạp hơn, mô hình khung nhìn được mong muốn vì nhiều lý do. Nó thể hiện dữ liệu của mô hình theo cách phù hợp hơn để hiển thị hoặc trong trường hợp này là xử lý mẫu.

Trong trường hợp bạn đang sử dụng mô hình dạng xem, bạn có thể dễ dàng trình bày danh sách theo cách tạo điều kiện cho mục tiêu của mình.

Mô hình:

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

Xem mô hình:

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

Danh sách lưu trữ thứ hai rất khó gõ nhưng cực kỳ đơn giản để tạo từ mã. Trong khi ánh xạ mô hình của bạn với mô hình dạng xem, chỉ cần thay thế mọi danh sách bạn cần firstlastcho bằng biểu diễn này.

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
}

Trong trường hợp danh sách không bị ràng buộc, bạn cũng chỉ có thể đặt firstvà bỏ qua last, vì một trong số chúng là đủ để tránh dấu phẩy ở cuối.

Sử dụng first:

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

Sử dụng last:

{{#numbers}}{{value}}{{^last}}, {{/last}}{{/numbers}}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.