Usando vírgula como separador de lista com AngularJS

179

Preciso criar uma lista de itens separados por vírgula:

  <li ng-repeat="friend in friends">
      <b ng-repeat="email in friend.email">{{email}}{{$last ? '' : ', '}}</b>...
  </li>

De acordo com a documentação do AngularJS, nenhuma instrução de fluxo de controle é permitida em expressões. É por isso que o meu {{$last ? '' : ', '}}não funciona.

Existe uma maneira alternativa de criar listas separadas por vírgula?

EDIT 1
existe algo mais simples que:

<span ng-show="!$last">, </span>
Franck Freiburger
fonte
5
Você sempre pode usar CSS para listas formato desta forma (então você não precisa modificar HTML quando seu chefe quer que eles em linhas separadas, etc.) - veja stackoverflow.com/questions/1517220/...
AlexFoxGill

Respostas:

338

Você poderia fazer assim:

<b ng-repeat="email in friend.email">{{email}}{{$last ? '' : ', '}}</b>

..Mas eu gosto da resposta do Philipp :-)

Andrew Joslin
fonte
Nem ($last && '' || ', ')sempre deve render ', '?
okm 15/05
15
Como okm acima, não consegui obter angular para avaliar corretamente $ last para true ou false dentro de um modelo. Eu usei esse: {{{true: '', false: ', '}[$last]}}. Esta técnica é mais flexível do que usar .joinporque permite que os elementos da lista a cada ser membros de uma matriz, como:<b ng-repeat="friend in friends">{{friend.email}}{{{true: '', false: ', '}[$last]}}</b>
Ryan Marcus
3
Atualizado para usar operadores ternários
Andrew Joslin
1
Como posso inserir e na matriz impressa para que minha matriz fique assim: John, Mike e Nil. Como obter esse formato sem usar a diretiva.
MaTya 29/07
Estou usando essa abordagem, pois ela me permite usar um filtro em cada valor da lista.
C Fairweather
231

Basta usar a função interna do Javascript join(separator)para matrizes:

<li ng-repeat="friend in friends">
  <b>{{friend.email.join(', ')}}</b>...
</li>
Philipp Reichart
fonte
21
Se você deseja separadores HTML-ish, provavelmente é hora de uma diretiva de gravação . Você também pode colocar HTML em join()e escapar desativar HTML, mas há um lugar especial no inferno para isso;)
Philipp Reichart
Bom, eu nem pensei em usá-lo dessa maneira.
Morango
@DavidKEgghead Eu imploro para diferir, jsfiddle.net/wuZRA . Como isso não funciona para você?
Philipp Reichart
2
@PhilippReichart desculpe pelo atraso. Aqui está um exemplo: jsfiddle.net/Sek8F - parece que você está direcionando uma string onde, como estou me referindo a um objeto.
Ravi Ram
101

Além disso:

angular.module('App.filters', [])
    .filter('joinBy', function () {
        return function (input,delimiter) {
            return (input || []).join(delimiter || ',');
        };
    });

E no modelo:

{{ itemsArray | joinBy:',' }}
sanusart
fonte
11
Esta resposta mostra "caminho angular" e deve ser marcada como a melhor.
Eugene Griaznov 16/09/14
14
Por que não salvar seis linhas e apenas fazer {{ itemsArray.join(', ') }}?
Philipp Reichart
12
Eu não tenho certeza re-escrever funções centrais JavaScript em AngularJS é realmente "o caminho Angular" ...
Michael Cole
1
Esta resposta mostra como Angular pode adicionar valor para arrays de objetos
Michael Cole
41

.list-comma::before {
  content: ',';
}
.list-comma:first-child::before {
  content: '';
}
<span class="list-comma" ng-repeat="destination in destinations">
                            {{destination.name}}
                        </span>

simbu
fonte
1
Isso parece da maneira mais "semântica", pois a escolha de usar uma lista separada por vírgula é inteiramente sobre apresentação. Poderia muito bem ter sido uma sub-lista.
Elliot Cameron
Esta foi a primeira solução que me veio à mente. Menos dependente do JavaScript.
precisa saber é o seguinte
10

Você pode usar CSS para corrigi-lo também

<div class="some-container">
[ <span ng-repeat="something in somethings">{{something}}<span class="list-comma">, </span></span> ]
</div>

.some-container span:last-child .list-comma{
    display: none;
}

Mas a resposta de Andy Joslin é melhor

Edit: Eu mudei de idéia, tive que fazer isso recentemente e acabei indo com um filtro de junção.

Chris Stephens
fonte
2
Eu iria para um filtro personalizado também, mas eu gosto da sua ideia :)
JBC
5

Eu acho que é melhor usar ng-if. ng-showcria um elemento no dome define-o display:none. Quanto mais domelementos você tiver, mais recursos o seu aplicativo se tornará e, em dispositivos com menos recursos, menos domelementos, melhor.

TBH <span ng-if="!$last">, </span>parece ser uma ótima maneira de fazê-lo. É simples.

the7erm
fonte
Eu gosto dessa abordagem, pois é simples e ainda suporta separadores baseados em html. Obrigado @ the7erm!
Alexkb 03/03
2

Como essa pergunta é bastante antiga e o AngularJS teve tempo de evoluir desde então, agora isso pode ser facilmente alcançado usando:

<li ng-repeat="record in records" ng-bind="record + ($last ? '' : ', ')"></li>.

Observe que estou usando em ngBindvez de interpolação {{ }}, pois é muito mais eficiente: ngBind só será executado quando o valor passado realmente mudar. Os colchetes {{ }}, por outro lado, serão sujos verificados e atualizados a cada $ digest, mesmo que não seja necessário. Fonte: aqui , aqui e aqui .

angular
  .module('myApp', [])
  .controller('MyCtrl', ['$scope',
    function($scope) {
      $scope.records = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    }
  ]);
li {
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MyCtrl">
  <ul>
    <li ng-repeat="record in records" ng-bind="record + ($last ? '' : ', ')"></li>
  </ul>
</div>

Em uma nota final, todas as soluções aqui funcionam e são válidas até hoje. Eu realmente sou encontrado por aqueles que envolvem CSS, pois esse é mais um problema de apresentação.

Cosmin Ababei
fonte
1

Gosto da abordagem da simbu, mas não me sinto confortável em usar o primeiro ou o último filho. Em vez disso, apenas modifico o conteúdo de uma classe de lista-vírgula repetida.

.list-comma + .list-comma::before {
    content: ', ';
}
<span class="list-comma" ng-repeat="destination in destinations">
    {{destination.name}}
</span>
Durrahan
fonte
0

Se você estiver usando o ng-show para limitar os valores, o processo {{$last ? '' : ', '}}não funcionará, pois ainda levará em consideração todos os valores.

<div ng-repeat="x in records" ng-show="x.email == 1">{{x}}{{$last ? '' : ', '}}</div>

var myApp = angular.module("myApp", []);
myApp.controller("myCtrl", function($scope) {
  $scope.records = [
    {"email": "1"},
    {"email": "1"},
    {"email": "2"},
    {"email": "3"}
  ]
});

Resulta na adição de uma vírgula após o "último" valor , pois com ng-show ele ainda leva em consideração todos os 4 valores

{"email":"1"},
{"email":"1"},

Uma solução é adicionar um filtro diretamente ao ng-repeat

<div ng-repeat="x in records | filter: { email : '1' } ">{{x}}{{$last ? '' : ', '}}</div>

Resultados

{"email":"1"},
{"email":"1"}
Mihai
fonte
Alguma sugestão sobre como resolver esse problema da mesma maneira no Angular 2 sem criar um pipe personalizado?
chaenu