除了在最后一个元素之后,如何在{{#each}}循环中的元素之间添加分隔符?

时间:2022-11-22 13:44:32

I have a Handlebars template where I'm trying to generate a comma-separated list of items from an array.

我有一个Handlebars模板,我正在尝试从数组生成以逗号分隔的项目列表。

In my Handlebars template:

在我的Handlebars模板中:

{{#each list}}
    {{name}} {{status}},
{{/each}}

I want the , to not show up on the last item. Is there a way to do this in Handlebars or do I need to fall back to CSS selectors?

我希望,不要出现在最后一项。有没有办法在Handlebars中执行此操作,还是需要回退到CSS选择器?

UPDATE: Based on Christopher's suggestion, this is what I ended up implementing:

更新:基于克里斯托弗的建议,这是我最终实现的:

var attachments = Ember.CollectionView.extend({
    content: [],
    itemViewClass: Ember.View.extend({
        templateName: 'attachments',
        tagName: 'span',
        isLastItem: function() {
            return this.getPath('parentView.content.lastObject') == this.get('content');
        }.property('parentView.content.lastObject').cacheable()
    })
}));

and in my view:

在我看来:

{{collection attachments}}

and the item view:

和项目视图:

{{content.title}} ({{content.size}}) {{#unless isLastItem}}, {{/unless}}

8 个解决方案

#1


48  

You can use standard CSS to do this:

您可以使用标准CSS执行此操作:

li:after {
    content: ',';
}

li:last-of-type:after {
    content: '';
}

I prefer separate rules, but a more concise if slightly less readable version (from @Jay in the comments):

我更喜欢单独的规则,但更简洁,如果可读性略低(来自评论中的@Jay):

li:not(:last-of-type):after {
    content: ',';
}

#2


101  

I know I'm late to the parts but I found a WAYYYY simpler method

我知道我迟到的部分,但我找到了一个更简单的方法

{{#unless @last}},{{/unless}}

#3


56  

Since Ember v1.11 you are able to get the index of an each using block parameters. In your case this would look something like this:

从Ember v1.11开始,您可以获得每个使用块参数的索引。在你的情况下,这将是这样的:

{{#each list as |item index|}}
    {{if index ", "}}{{item.name}} {{item.status}}
{{/each}}

The first index value will be 0 which will evaluate to false and will not be added, all subsequent values will evaluate to true which will prepend a separator.

第一个索引值将为0,将评估为false并且不会添加,所有后续值将计算为true,这将预先设置分隔符。

#4


5  

I realize this is a year old but I had a similar problem and wound up here. In my case, I was actually dealing with an array. So, here's my solution.

我意识到这已经有一年了,但我遇到了类似的问题并且在这里结束了。就我而言,我实际上正在处理数组。所以,这是我的解决方案。

Handlebars.registerHelper('csv', function(items, options) {
    return options.fn(items.join(', '));
});

// then your template would be
{{#csv list}}{{this}}{{/csv}}

I was going for a simple and elegant solution that keeps the csv logic in the template.

我想要一个简单而优雅的解决方案,将csv逻辑保留在模板中。

#5


4  

With ember 2.7 you can do this after you install ember-truth-helpers:

使用ember 2.7,您可以在安装ember-truth-helpers之后执行此操作:

ember install ember-truth-helpers

and then your template will look like this:

然后你的模板将如下所示:

{{#each model as |e|}}
    {{e}}{{#unless (eq e model.lastObject)}}, {{/unless}}
{{/each}}

#6


3  

I got this working with a modified version of freak3dot's answer:

我得到了这个与freak3dot的修改版本的答案:

handlebars.registerHelper('csv', function(items, options) {
  return items.map(function(item) {
    return options.fn(item)
  }).join(', ')
})

(This is a node app, so change the map accordingly to underscore or whatever if you're building in the browser)

(这是一个节点应用程序,因此如果您在浏览器中构建,请相应地将地图更改为下划线或其他任何内容)

Allows for formatting objects between each comma:

允许在每个逗号之间格式化对象:

{{#csv players}
  {{firstName}} {{lastName}}
{{/csv}}

Edit: Here's a more flexible version. Join a list of things on an arbitrary separator.

编辑:这是一个更灵活的版本。在任意分隔符上加入事物列表。

handlebars.registerHelper('join', function(items, separator, options) {
  return items.map(function(item) {
    return options.fn(item)
  }).join(separator)
})

And template:

和模板:

{{#join players ' vs '}
  {{firstName}} {{lastName}}
{{/join}}

#7


3  

I have created sep block helper:

我创建了sep块帮助器:

Handlebars.registerHelper("sep", function(options){
    if(options.data.last) {
        return options.inverse();
    } else {
        return options.fn();
    }
});

Usage:

用法:

{{#each Data}}
   {{Text}}{{#sep}},{{/sep}}
{{/each}}

Supports else statement.

支持其他声明。

#8


2  

Maybe for this context, you should be creating a view for the collection, not an iteration of views on the member items. In this case, a Handlebar iterator is overkill. In my example below, changes to the firstName or lastName on the Person objects will be bound to the list and update the view.

也许对于此上下文,您应该为集合创建视图,而不是成员项的视图迭代。在这种情况下,Handlebar迭代器是过度的。在下面的示例中,对Person对象的firstName或lastName的更改将绑定到列表并更新视图。

Template:

模板:

{{App.listController.csv}}

Javascript:

使用Javascript:

App = Ember.Application.create();

var Person = Ember.Object.extend({
    firstName: null,
    lastName: null
});

var bob = Person.create({
    firstName: "bob",
    lastName: "smith"
});

var ann = Person.create({
    firstName: "ann",
    lastName: "doe"
});

App.listController = Ember.Object.create({
    list: [bob, ann],
    csv: Ember.computed(function () {
        var arr = [];
        this.get('list').forEach(function (item, index, self) {
            arr.push(item.firstName + ' ' + item.lastName);
        })
        return arr.join(',');
        }).property('list.@each.firstName', 'list.@each.lastName')
});
// any changes to bob or ann will update the view
bob.set('firstName', 'tim');
// adding or removing from the array will update the view
App.listController.get('list').pushObject(Person.create(firstName: "Jack", lastName:"Dunn"});

Below is my original answer, that didn't work for this context.

以下是我原来的答案,这对于这种情况不起作用。

You should be able to do this with a helper:

您应该能够使用帮助程序执行此操作:

Handlebars.registerHelper('csv', function(items, options) {
  var out = "";
  for(var i=0, l=items.length; i<l; i++) {
    out += options.fn(items[i]);
    if (i < l - 1) {
        out += ',';
    }
    // might want to add a newline char or something
  } 
  return out;
});

// then your template would be
{{#csv list}} {{name}} {{status}} {{/each}}

#1


48  

You can use standard CSS to do this:

您可以使用标准CSS执行此操作:

li:after {
    content: ',';
}

li:last-of-type:after {
    content: '';
}

I prefer separate rules, but a more concise if slightly less readable version (from @Jay in the comments):

我更喜欢单独的规则,但更简洁,如果可读性略低(来自评论中的@Jay):

li:not(:last-of-type):after {
    content: ',';
}

#2


101  

I know I'm late to the parts but I found a WAYYYY simpler method

我知道我迟到的部分,但我找到了一个更简单的方法

{{#unless @last}},{{/unless}}

#3


56  

Since Ember v1.11 you are able to get the index of an each using block parameters. In your case this would look something like this:

从Ember v1.11开始,您可以获得每个使用块参数的索引。在你的情况下,这将是这样的:

{{#each list as |item index|}}
    {{if index ", "}}{{item.name}} {{item.status}}
{{/each}}

The first index value will be 0 which will evaluate to false and will not be added, all subsequent values will evaluate to true which will prepend a separator.

第一个索引值将为0,将评估为false并且不会添加,所有后续值将计算为true,这将预先设置分隔符。

#4


5  

I realize this is a year old but I had a similar problem and wound up here. In my case, I was actually dealing with an array. So, here's my solution.

我意识到这已经有一年了,但我遇到了类似的问题并且在这里结束了。就我而言,我实际上正在处理数组。所以,这是我的解决方案。

Handlebars.registerHelper('csv', function(items, options) {
    return options.fn(items.join(', '));
});

// then your template would be
{{#csv list}}{{this}}{{/csv}}

I was going for a simple and elegant solution that keeps the csv logic in the template.

我想要一个简单而优雅的解决方案,将csv逻辑保留在模板中。

#5


4  

With ember 2.7 you can do this after you install ember-truth-helpers:

使用ember 2.7,您可以在安装ember-truth-helpers之后执行此操作:

ember install ember-truth-helpers

and then your template will look like this:

然后你的模板将如下所示:

{{#each model as |e|}}
    {{e}}{{#unless (eq e model.lastObject)}}, {{/unless}}
{{/each}}

#6


3  

I got this working with a modified version of freak3dot's answer:

我得到了这个与freak3dot的修改版本的答案:

handlebars.registerHelper('csv', function(items, options) {
  return items.map(function(item) {
    return options.fn(item)
  }).join(', ')
})

(This is a node app, so change the map accordingly to underscore or whatever if you're building in the browser)

(这是一个节点应用程序,因此如果您在浏览器中构建,请相应地将地图更改为下划线或其他任何内容)

Allows for formatting objects between each comma:

允许在每个逗号之间格式化对象:

{{#csv players}
  {{firstName}} {{lastName}}
{{/csv}}

Edit: Here's a more flexible version. Join a list of things on an arbitrary separator.

编辑:这是一个更灵活的版本。在任意分隔符上加入事物列表。

handlebars.registerHelper('join', function(items, separator, options) {
  return items.map(function(item) {
    return options.fn(item)
  }).join(separator)
})

And template:

和模板:

{{#join players ' vs '}
  {{firstName}} {{lastName}}
{{/join}}

#7


3  

I have created sep block helper:

我创建了sep块帮助器:

Handlebars.registerHelper("sep", function(options){
    if(options.data.last) {
        return options.inverse();
    } else {
        return options.fn();
    }
});

Usage:

用法:

{{#each Data}}
   {{Text}}{{#sep}},{{/sep}}
{{/each}}

Supports else statement.

支持其他声明。

#8


2  

Maybe for this context, you should be creating a view for the collection, not an iteration of views on the member items. In this case, a Handlebar iterator is overkill. In my example below, changes to the firstName or lastName on the Person objects will be bound to the list and update the view.

也许对于此上下文,您应该为集合创建视图,而不是成员项的视图迭代。在这种情况下,Handlebar迭代器是过度的。在下面的示例中,对Person对象的firstName或lastName的更改将绑定到列表并更新视图。

Template:

模板:

{{App.listController.csv}}

Javascript:

使用Javascript:

App = Ember.Application.create();

var Person = Ember.Object.extend({
    firstName: null,
    lastName: null
});

var bob = Person.create({
    firstName: "bob",
    lastName: "smith"
});

var ann = Person.create({
    firstName: "ann",
    lastName: "doe"
});

App.listController = Ember.Object.create({
    list: [bob, ann],
    csv: Ember.computed(function () {
        var arr = [];
        this.get('list').forEach(function (item, index, self) {
            arr.push(item.firstName + ' ' + item.lastName);
        })
        return arr.join(',');
        }).property('list.@each.firstName', 'list.@each.lastName')
});
// any changes to bob or ann will update the view
bob.set('firstName', 'tim');
// adding or removing from the array will update the view
App.listController.get('list').pushObject(Person.create(firstName: "Jack", lastName:"Dunn"});

Below is my original answer, that didn't work for this context.

以下是我原来的答案,这对于这种情况不起作用。

You should be able to do this with a helper:

您应该能够使用帮助程序执行此操作:

Handlebars.registerHelper('csv', function(items, options) {
  var out = "";
  for(var i=0, l=items.length; i<l; i++) {
    out += options.fn(items[i]);
    if (i < l - 1) {
        out += ',';
    }
    // might want to add a newline char or something
  } 
  return out;
});

// then your template would be
{{#csv list}} {{name}} {{status}} {{/each}}